拡張メソッドでNUnitを快適にする

public static class Extention {
    public static void should_be<T>(this T th,T expected) {Assert.AreEqual(th,expected);}
}

で、

//before
Assert.AreEqual(obj.DoSomething(),"result");
Assert.That(obj.DoSomething(),Is.EqualTo("result")); //2.4の新記法らしい。長くなってる……><

//after
obj.DoSomething().should_be("result");

とてもかわいいですね。


そしてこれは序の口。拡張メソッドを使えば例外テストも自然に記述できる。
今までは

//before
[ExpectedException(typeof(ArgumentException))]
public static ExceptionTest() {
    obj.DoIllegal();
}

//あるいは
try {
    obj.DoIllegal();
    Assert.Fail("ArgumentException expected");
} catch(ArgumentException) {
}

これがこう書ける

//after
This.Operation( delegate{ obj.DoIllegal(); } ).throws<ArgumentException>();

すごく自然!
ちょうかわいい!


実装はこんなかんじ。

public static class This {
    public static OperationHolder Operation(OperationDelegate op) {
        return new OperationHolder(op);
    }
    public delegate void OperationDelegate();
    public class OperationHolder {
        public OperationHolder(OperationDelegate o) { op = o; }
        public OperationDelegate op;
        public void throws<T>() where T:Exception {
            try {
                op();
                Assert.Fail("Exception "+typeof(T).Name+" expected but nothing");
            } catch (T) {
                //success
            } catch (Exception e) {
                if (e.GetType().IsKindOf(typeof(AssertionException))) throw; //NUnitが使ってる例外
                Assert.Fail("Exception "+typeof(T).Name+" expected but "+e.GetType().Name);
            }
        }
    }
}
public static class TypeExtention {
    public static bool IsKindOf(this Type t1,Type t2) {
        return t1==t2 || t1.IsSubclassOf(t2);
    }
}

ここまで書いてから上の例は拡張メソッドと特に関係なくC#2.0でも可能なことに気づいたが、なんにしろC#はかわいいので問題はない。