ずいぶんブログを閉鎖していましたが、不定期にプログラミングの事などをまた書きたいと思います。
今回は C# の UT(ユニットテスト)で、Mock を使った呼び出し回数テストに関して、書きたいと思います。まずテストするコードからです。
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Sample aSample = new Sample(); aSample.DoSomething(); } } }
簡単なコンソールアプリです。Main にコードをたくさん書く人がいますが、クラスメソッドだらけになるので激しく推奨しません。
行いたい処理は別クラスに書き、はやく Main から離れましょう。
namespace ConsoleApplication1 { public class Sample { OutputLog _log; public Sample() { _log = new OutputLog(); } public bool DoSomething() { _log.Error("debug error"); return true; } } }
Sample クラスは、実際に処理を行うクラスです。今回は DoSomethig メソッド内で OutputLog.Error() の呼び出し回数をテストしたいと思います。
using System; namespace ConsoleApplication1 { public class OutputLog { public void Error(string msg) { Console.Error.WriteLine(msg); } } }
OutputLog クラスです。今回はコンソールアプリなので、ログはコンソールにエラー出力するだけの簡単なコードです。
以上で準備は完了です。
テストプロジェクトを作って、Mock をダウンロードしてテストプロジェクトの参照に設定します。詳細は省きます。
using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; namespace ConsoleApplication1.Tests { [TestClass()] public class SampleTests { [TestMethod()] public void DoSomethingTest() { Mock<OutputLog> mock = new Mock<OutputLog>(); mock.Setup(m => m.Error("debug error")); Sample aSample = new Sample(); aSample.DoSomething(); mock.Verify(m => m.Error("debug error"), Times.Once()); } } }
OutputLog クラスの Error メソッドが、引数 "debug error" で一度だけ呼び出されているかテストするコードはこのような風に書けます。
1点目の注意として、呼び出し回数をテストしたいメソッドは virtual にする必要(virtual にするのが簡単です)があります。
using System; namespace ConsoleApplication1 { public class OutputLog { public virtual void Error(string msg) // <--- virtual 追加 { Console.Error.WriteLine(msg); } } }
2点目の注意として、mock に対して Error メソッドを呼ばないと実行回数は検査できません。
mock.Object を Sample のコンストラクタに渡し、OutputLog を差し替えます。
using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; namespace ConsoleApplication1.Tests { [TestClass()] public class SampleTests { [TestMethod()] public void DoSomethingTest() { Mock<OutputLog> mock = new Mock<OutputLog>(); mock.Setup(m => m.Error("debug error")); Sample aSample = new Sample(mock.Object); // <--- mock.Object を渡す aSample.DoSomething(); mock.Verify(m => m.Error("debug error"), Times.Once()); } } }
ですので Sample クラスは OutputLog を引数に受けるコンストラクタが必要になり、
引数で受け取った OutputLog を _log に設定します。
namespace ConsoleApplication1 { public class Sample { OutputLog _log; public Sample() { _log = new OutputLog(); } public Sample(OutputLog log) // <--- 追加 { _log = log; } public bool DoSomething() { _log.Error("debug error"); return true; } } }
DoSomethingTest() を実行してみるとテストが成功します。
OutputLog.Error(string) が引数 "debug error" で一度だけ呼び出されている事が確認できました。
なお、実際の業務で UT を書く場合は、いろんな複雑な事情があって、こんなに簡単には行かない事をお断りしておきますw
今回のポイント
・Setup するメソッドは virtual にする。
・Verify するには Mock 用に生成したインスタンスで差し替えて、テストメソッドを実行する必要がある。
以上です。
しかしブログで「わかりやすい説明になるように文章を書く」というのは、
「きれいでわかりやすいコードを書く」技術にも繋がると思うので良いですね。
言語が違うだけで本質は同じだと思います。
ではまた。