2010年6月27日日曜日

Typemock--コンストラクタの呼び出しチェックが・・・

テスタビリティの悪いシステムに後付のユニットテストを書く事になりそうなので、モッキング・フレームワークを検討中。

フリーの Moq やら何やらは、バーチャル・メソッドしかモックできないなんて制約があって、最初から最大限にテスタビリティを考慮したシステムにしか適用できそうにない。それ以前に、そもそも.net フレームワーク自体がテスタビリティを下げる犯人でもあったりして、悩ましい。

そんなこんなで、Typemock Isolator という有料のものを見つけて、個人ライセンスで試用しているが、どうやらこれしか選択肢はないらしい。静的メソッドや sealed までモックテストできたりする。

さすがに有料だけあって、非常に強力なのだが、ちょっとモッキングが難しいパターンを発見したのでメモしておく。
class Class1
{
    public string Name {get; set;}
    public Class1(string name)
    {
        this.Name = name;
    }
    public void ShowName()
    {
        MessageBox.Show(Name);
    }
}
class Program
{
    static void Main(string[] args)
    {
        Class1 class1 = new Class1(args[0]);
        class1.ShowName();
    }
}

上記のようなコードで、Main()メソッドの後付をテストコードを書くとすると、モックテストとしての要点は、
  1. Main()が引数の先頭要素を Class1 コンストラクタに渡している事を検証する
  2. 生成したインスタンスの ShowName()メソッドを呼ぶ事を検証する。
  3. 但し、実物の ShowName()は実際に呼ばれてはいけない。
というものになる。

ここで仮に、1)の要件が無いとすると、以下のような EDSL 風のコードで2)と3)をテストできる。
[Test, Isolated]
public void Test1()
{
    string[] args = {"arg1"};
    //Arrange
    var fake = Isolate.Fake.Instance<Class1>();
    Isolate.Swap.NextInstance<Class1>().With(fake);
    //Act
    Isolate.Invoke.Method<Program>("Main", new object[] { args });
    //Assert
    Isolate.Verify.WasCalledWithAnyArguments(() => fake.ShowName());
}

テスト対象メソッドの中で生成されるオブジェクトを、実行前に生成した贋物にすりかえてしまえるのが面白い。

ところが上記のような、Isolate.~~(AAA APIと言うらしい)を使う方法だと、要点 1)のコンストラクタにへの引数を検証するやり方がどうも見当たらない。

調べると、Typemockには AAA API の他に、より古いAPIセットがあって、こっちにはコンストラクタ引数の検証メソッドがあるという。
以下のようなコードで、要点1)を検証できる。
[Test]
public void Test2()
{
    string[] argument1 = {"arg1"};

    MockManager.Init();
    Mock theMock = MockManager.Mock<Class1>(Constructor.NotMocked);

    theMock.ExpectConstructor().Args(argument1[0]);
    theMock.ExpectCall("ShowName", 1);

    Isolate.Invoke.Method<Program>("Main", new object[] { argument1 });

    MockManager.Verify();
}
ところがTest1()とTest2()を、どうしても一つのテストメソッドにマージできない。
Test2()の古いAPIセットを使う方式だと、一個のメソッドで、1)~3)までテストする事もできない事はなさそうだが、陳腐化しはじめているし、そもそもTest1()のAAA APIが推奨されているし、やっぱり嫌だ。

上のような状況の後付テストを書くときは、1メソッドに対して2系統のテストを書く事になるのか・・・
それとも、AAA に未発見の API があるのか・・・
後者に期待したいが。

====
と言うかそれ以前に、これを使うとした場合、プロジェクトとして調達するためにステークホルダに説明しなければならない事として、
  • 現状のシステムのテスタビリティが低すぎる事。
  • モックテストとは何か、その必要性はどんなものか
  • 既存の書きかけのテストコードが、下手糞すぎて使えない事
  • functional test と unit test が混同されていたり(違いはここ)、何のテスト方針も定まっていない事
などなど、いろいろあって、そこから面倒くさい。

0 件のコメント:

コメントを投稿