何をテストしたいのか? をハッキリする
問題
同じ内容のテストを2度以上書いてしまった時、以下の問題が発生している可能性があります。
- 何をテストしたいのかハッキリしていない。
- 技術的負債を抱えたコードを書いている。
例
ユーザーが、オレンジを食べるメソッドを作ります。
これをTDDで実装します。
テスト対象は、UserクラスのEatメソッドです。
public class User { // オレンジを食べます public void Eat(Orange orange) { throw new NotImplementedException(); } } [TestFixture] public class UserTest { [Test] public void Eat_Test() { //いまからテストかくところ } }
Orangeクラスには既に、食べられるメソッドが実装してあるものとします。
すでにテストも書いてあります。
Orangeクラスは食べられると、Volumeプロパティが1減るそうです。
public class Orange { /// <summary> /// ユーザにより、食べられます。 /// </summary> /// <param name="user">ユーザ</param> public void EatenBy(User user) { this.Volume = this.Volume - 1; //...他、食べられた処理など } } [TestFixture] public class OrangeTest { [Test] public void EatenBy_Test() { var orange = new Orange() { Volume = 3 }; var user = new User(); // 実行 orange.EatenBy(user); int expect = 2; Assert.AreEqual(expect, orange.Volume); } }
普通の人は、このメソッドを利用して、UserのEatメソッドを実装しようと思います。
TDD開始!!
同じテストを2度書いてしまう、まずいテストの書き方。↓
[TestFixture] public class UserTest { [Test] public void Eat_Test() { var user = new User(); var orange = new Orange() { Volume = 3 }; //実行 user.Eat(orange); int expect = 2; Assert.AreEqual(expect, orange.Volume); } }
Orangeのテストコードと同じようなことを書いています。
よりよい書き方はこうです。↓
[TestFixture] public class UserTest { [Test] public void Eat_Test() { var user = new User(); Mock<Orange> orangeMock = new Mock<Orange>(); orangeMock.Setup(orange => orange.EatenBy(user)); //実行 user.Eat(orangeMock.Object); orangeMock.VerifyAll(); } }
おまけの実装コード
public class User { // オレンジを食べます public void Eat(Orange orange) { orange.EatenBy(this); } }
テストをしたい内容は、
OrangeのEatenByを正しい引数で呼び出しているか?
であり、
ユーザがオレンジを食べたら、オレンジの量が1コへっているかどうか?
ではありません。
また、このまずいテストの書き方は、1つ技術的負債を抱えています。
(1コ減るのではなくて、2コ減らして!と仕様変更が来た場合、
OrangeTestと、UserTestのテストを書きなおさなくてはなりません。)
おしまい
上の例では、何をテストしたいのか、はっきりしないままコードを書いたために、
よくないコードが生まれてしまいました。
TDDでは、何をテストしたいのか?をちゃんとハッキリすることが大事。
補完
テストツールはNUnit、Moqを使っています。
例のコードのままだと、以下のエラーがでます。
failed: System.NotSupportedException : Invalid setup on a non-virtual (overridable in VB)
UserのEatメソッドを、virtual にするとモックが機能します。
TDDサイト
TDD.NET http://www.tdd-net.jp/
Strategic Choice http://d.hatena.ne.jp/asakichy/ テスト駆動開発カテゴリ
TDDアンチパターン http://blog.james-carr.org/2006/11/03/tdd-anti-patterns/
...ちゃんと勉強しなかったために、無駄な時間を過ごしました orz