忘れてた

C#と諸々 パブリックプロパティ (もしくはパブリックフィールド) の善悪

GUI 周りと DB 周りの他に、ユニットテストにも関わってくるね。
ユニットテストでも恩恵を得られるけれど、たまに一工夫必要になる。


こんなクラスと

public sealed class Hoge
{
    public Hoge(string aaa, string bbb)
    {
    }
    private string _aaa;
    private string _bbb;
    public void Present(Receiver receiver)
    {
        receiver(this._aaa, this._bbb);
    }
    public delegate void Receiver(string aaa, string bbb);
}

こんなクラスがあったとして、

public sealed class Fuga
{
    public Fuga(IPiyo piyo)
    {
        this._piyo = piyo;
    }

    private readonly IPiyo _piyo;

    public void Foo()
    {
        this._piyo.Bar(new Hoge("aiueo", "abcde"));
    }
}

Fuga を IPiyo のモックを使ってテストする時。
プロパティが用意してあればこんな風に書けるけど、

public void Test1()
{
    DynamicMock piyoMockery = new DynamicMock(typeof(IPiyo));
    Fuga fuga = new Fuga((IPiyo)piyoMockery.MockInstance);

    piyoMockery.Expect("Bar", Has.Property("Aaa", "aiueo") & Has.Property("Bbb", "abcde"));
    fuga.Foo();
    piyoMockery.Veryfy();
}

ないので書けない。
そこで、Constraint クラスを自作する。

private sealed class HogeEqualConstraint : Constraint
{
    public HogeEqualConstraint(string aaa, string bbb)
    {
        this._aaa = aaa;
        this._bbb = bbb;
    }

    private readonly string _aaa;
    private readonly string _bbb;

    public override bool Matches(object actual)
    {
        if (!(actual is Hoge))
        {
            return false;
        }

        Hoge.Receiver receiver = delegate(string aaa, string bbb)
        {
            Assert.That(aaa, Is.EqualTo(this._aaa));
            Assert.That(bbb, Is.EqualTo(this._bbb));
        };
        ((Hoge)actual).Present(receiver);
        return true;
    }

    public override void WriteDescriptionTo(MessageWriter writer)
    {
    }
}

public void Test1()
{
    DynamicMock piyoMockery = new DynamicMock(typeof(IPiyo));
    Fuga fuga = new Fuga((IPiyo)piyoMockery.MockInstance);

    piyoMockery.Expect("Bar", new HogeEqualConstraint("aiueo", "abcde"));
    fuga.Foo();
    piyoMockery.Veryfy();
}

他にも、もっと汎用的な Constraint クラスを自作するという手もある。
あと、Hoge が Equals メソッドをオーバーライドしている場合は、Constraint を自作する必要はなし。