2

Visual Studio に組み込まれている C# の単体テスト機能を使用して単体テストを行いたいさまざまな方法があります。物事はかなり順調に進んでいますが、特定の関数呼び出しへの依存関係を「スタブアウト」したいシナリオに遭遇しました。

つまり、次の形式のメソッドがいくつかあります。

public class ClassWithMethodsIWantToUnitTest 
{
    public void myFcn(object someArg)
    {
        ...
        LoggerService.Instance.LogMessage("myMessage");
        ...
    }
}

基本的に、単体テストで「LogMessage」の呼び出しが発生したことを確認するだけです。実際にログファイルなどをチェックしたくありません。LoggerService 行がヒットして実行されたかどうかを確認する方法が必要です。

LoggerService はシングルトンです。可能であれば、単体テストのためだけにコードを変更したくありません。

この問題の形式に基づいて、ユニット テストで何らかの方法でコードを制御できるように思われます。つまり、単体テストに使用できるように、LogMessage の偽バージョンを作成する方法はありますか? 可能であれば、「実際の」LogMessage関数を呼び出したくありません。コードが関数を呼び出したパスにヒットしたことをテストしたいだけです。

これは意味がありますか?これは可能ですか?

4

3 に答える 3

6

それは確かに理にかなっており、未知の問題ではありません。

残念ながら、依存性注入を受け入れるように、おそらくコードを変更する必要があります。つまり、テストするときは、本物ではなく、特別に作成されたテストオブジェクト(モック)を挿入できる必要があります。あなたの場合、それはおそらくLoggerService.Instance特別なモックオブジェクトに設定できることを意味します。

次に必要なのは、テストする偽のロガーインスタンスです。おそらく、呼び出し元の動作をチェックするために設定できる特別なオブジェクトであるモックが必要です。いくつかの模擬フレームワークがありますが、独自のフレームワークを作成するのではなく、1つを使用することを強くお勧めします。

于 2012-08-18T16:25:38.330 に答える
4

Anders の答えは間違いなく、問題にアプローチする「標準的な」方法でしたが、.NET 4.5 には 2 番目のオプションがあります。

Fakes フレームワーク。

メソッドの実際の実装の代わりに実行するデリゲートを受け入れる "偽の" アセンブリを単体テスト プロジェクトに追加できます。を使用した例を次に示します。File.ReadAllText

    [TestMethod]
    public void Foo()
    {
        using (ShimsContext.Create())
        {
            ShimFile.ReadAllTextString = path => "test 123";
            var reverser = new TextReverser();
            const string expected = "321 tset";
            //Act
            var actual = reverser.ReverseSomeTextFromAFile(@"C:\fakefile.txt");
            //Assert
            Assert.AreEqual(expected, actual);
        }
    }

そのテスト メソッドが行っていることは、一時的に ( の範囲内で) の実装を私が提供したラムダにShimsContext置き換えることです。File.ReadAllTextこの場合、ReadAllTextが呼び出されるたびに、文字列 "test 123" が返されます。

通常の DI よりも遅いですが、シングルトンの特定の実装に完全に結び付けられている場合は、まさに必要なものになる可能性があります。詳しくはこちらをご覧ください。

于 2012-08-18T16:57:03.157 に答える
3

アンダースが言ったこと。

MoqRhinoMocksは、いくつかの一般的なモッキング フレームワークです。

そして、ロガーの依存関係がクラスに注入されるようにコードを変更します。

public class ClassWithMethodsIWantToUnitTest 
{
      public ClassWithMethodsIWantToUnitTest(ILoggerService logger)
      {}

      public void myFcn(object someArg)
      {
         ...
          logger.LogMessage("myMessage");
         ...
      }
}

または似たようなもの。DI フレームワークは、必要なときにロガーをクラスに自動的に挿入できます。基本的に、DI フレームワークは自動的に呼び出します

new ClassWithMethodsIWantToUnitTest(LoggerService.Instance);
于 2012-08-18T16:59:49.067 に答える