自動化された単体テストを行いたいという趣旨であれば、設計を見直す必要があります。
この例で一番シンプルにやるとすれば
C#
1public interface IMessageBox {
2 void Show(string message);
3}
というインターフェイスを用意して、
C#
1public class MessageBoxUI : IMessageBox {
2 public void Show(string message) {
3 MessageBox.Show(message);
4 }
5}
実際に画面を出す処理をこのインターフェイスを実装した別のクラスに分離し
C#
1public static bool TestFunction(int a, int b, IMessageBox messageBox)
2{
3 bool result;
4
5 if(a == 1 && b == 1)
6 {
7 messageBox("1です")
8 result = true;
9 }
10 else)
11 {
12 messageBox("1以外です")
13 result = false;
14 }
15
16
17 return result;
18}
このメソッド内ではインターフェイスに対して操作を行います。
呼び出し側は
C#
1var msgBox = new MessageBoxUI();
2TestFunction(1, 1, msgBox);
のように「実際に表示を行うオブジェクト」を生成して呼び出します。(最後に注記あり)
これを「IoC = Inversion of Control(制御の反転)」と言います。
このように作っておくと、テストでは
C#
1class MockMessageBox : IMessageBox {
2 public void Show(string message) {
3 System.Diagnostics.Debug.WriteLine(message);
4 }
5}
というモッククラスを作ることで
C#
1public void FunctionTests_正常系_両方が1の時True()
2{
3 var mockMessagebox = new MockMessageBox();
4 boole value = TestFunction(1, 1, mockMessageBox);
5 Assert.AreEqual(true, value);
6}
という感じでテスト可能になります。
こうしておくと、モッククラス側を例えば
C#
1class MockMessageBox : IMessageBox {
2
3 public string Message;
4
5 public void Show(string message) {
6 this.Message = message;
7 }
8}
のようにしておけば
C#
1public void FunctionTests_正常系_両方が1の時True()
2{
3 var mockMessagebox = new MockMessageBox();
4 var expectMessage = "1です";
5 boole value = TestFunction(1, 1, mockMessageBox);
6 Assert.AreEqual(true, value);
7 Assert.AreEqual(expectMessage, mockMessageBox.Message);
8}
といった感じで、実際に依存先のオブジェクトが呼び出された処理結果も検証できます。
注:
テストしたいコードは「画面の表示」に対して依存関係がなくなりますが、こうすると呼び出し側がこの「画面の表示」用のオブジェクトを作る必要があり、そちら側のテストが難しくなる事もあると思います。
そういった問題を解決する方法が「DI = Dependency Injection(依存性の注入)」といって、やり方は様々ですが、それを実現するためのフレームワーク(DIコンテナ)もたくさんあります。
(DryIoc, autofac, Unity(ゲーム開発等のやつとは無関係))
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/05/23 01:44
2019/05/23 04:40