miso_soup3 Blog

主に ASP.NET 関連について書いています。

1アサート 1失敗

単体テストのコードを書く上で、重要だと思うことのうち1つを書きます。
それは、TDDの手順の1つでもある、

”失敗するテストを書く”
です。

TDDまではいかなくてもいいから、とにかく単体テストコードを書きたい、
と思っている方や、

TDDに慣れすぎて、我流になりそうになっている方
にお伝えしたいです。

失敗するテストを書かないとどうなるか?

テストコードを書いた時間が無駄になります。
ミスのあるテストコードを書いてしまい、テストとしての役割を失います。

テストされていないので、実装側でミスがあってもわかりません。
さらに、開発者は”テスト成功”と思っているので、テストを書かないことより状況は悪いです。

よくあるテストコードのミス

間違ったAssert文を書いたり・・・
Assert.AreEqual(expect.PersonNumber, actual.PersonNumber);
Assert.AreEqual(expect.PersonNumber, actual.ProjectNumber);
// ↑ PeronNumberとProjectNumberを間違える。

Assert.AreEqual(expect.PersonNumber, expect.PersonNumber);
// ↑ おまえは何を言っているんだ
そもそもテスト対象を間違えていたり・・・
// act
Service.Search(request)
// ↑本当はSearchInPageメソッドをテストしなくてはいけないけど、
//   voidだったりすると気付かない。
Verify()を忘れたり・・・・
MyRepositoryMock.Setup(r => r.FindById(int)).Return(~~~);

//Verifyを忘れる+他のミス=テストが”成功”となる場合がある。

どうするか

テストを走らせて、”失敗”を確認してから、実装コードを書きます。

1アサート 1失敗

下のようなよくある検索パラメータは、
必ず1つずつAssert文を書き、失敗を確認してから、実装コードを触ります。
成功したら初めて、次のAssert文を書きます。

Assert.AreEqual(expect.PersonNumber, actual.PersonNumber);
Assert.AreEqual(expect.ProjectNumber, actual.ProjectNumber);
Assert.AreEqual(expect.Name, actual.Name);
Assert.AreEqual(expect.ProjectNumber, actual.ProjectNumber);

// ↓みたいなコードは、”成功”となるので、間違いに気がつきます。
Assert.AreEqual(expect.PersonNumber, expect.PersonNumber);

1アサート1メソッド、という言葉は、この問題をも片付けてくれます。

最初は throw new Notimplementedexception();

どんなメソッド、プロパティも、throw new Notimplementedexception();
から始めます。

テスト失敗を確認した後、throw ... を外し、すぐにテスト”成功”を確認します。

モックも1つずつ確認

モックの呼び出しも、大事なテスト項目だったりします。
モックを書いた後は、”このモック呼び出されていないよー”という、”失敗”を確認すると良いと思います。

さらにUP

テスト”失敗”だけではなく、失敗した”理由”も確認します。

TDDになれると、テスト”失敗”だけを目視し、失敗の”理由”をスルーしてしまいます。
テスト失敗の”理由”がちゃんと意図したものであった場合、テストの書き方はきっと正解です。

//良くないかもしれない例
Assert.AreEqual(expect.Id, response.Persons.First().Id);

//こっちの方がよいと思う例
Assert.IsNotNull(response);
Assert.IsNotNull(response.Persons);
var actual = response.Persons.First();
Assert.AreEqual(expect.Id, actual.Id);