16

現在、モック オブジェクトの概念を単体テストに導入し始めています。特に、Moq フレームワークを使用しています。しかし、私が気付いたことの 1 つは、このフレームワークを使用してテストしているクラスのコード カバレッジが突然 0% になっていることです。

クラスをモックしているだけなので、実際のクラス自体を実行していないことがわかりました....しかし、これらのテストを作成し、コードカバレッジが正確な結果を返すようにするにはどうすればよいですか? モックを使用する一連のテストと、クラスを直接インスタンス化するための一連のテストを作成する必要がありますか。

気づかないうちに何か間違ったことをしているのではないでしょうか?

「MyClass」というクラスを単体テストしようとしている例を次に示します。

using Moq;
using NUnitFramework;

namespace MyNameSpace
{
    [TestFixture]
    public class MyClassTests
    {

        [Test]
        public void TestGetSomeString()
        {
            const string EXPECTED_STRING = "Some String!";

            Mock<MyClass> myMock = new Mock<MyClass>();
            myMock.Expect(m => m.GetSomeString()).Returns(EXPECTED_STRING);

            string someString = myMock.Object.GetSomeString();

            Assert.AreEqual(EXPECTED_STRING, someString);
            myMock.VerifyAll();

        }

    }

    public class MyClass
    {
        public virtual string GetSomeString()
        {
            return "Hello World!";
        }
    }
}

私が何をすべきか知っている人はいますか?

4

3 に答える 3

17

モック オブジェクトを正しく使用していません。モック オブジェクトを使用しているときは、実際のオブジェクトを実際に使用せずに、コードが他のオブジェクトとどのように相互作用するかをテストすることを意味していました。以下のコードを参照してください。

using Moq;
using NUnitFramework;

namespace MyNameSpace
    {
        [TestFixture]
        public class MyClassTests
        {

            [Test]
            public void TestGetSomeString()
            {
                const string EXPECTED_STRING = "Some String!";

                Mock<IDependance> myMock = new Mock<IDependance>();
                myMock.Expect(m => m.GiveMeAString()).Returns("Hello World");

                MyClass myobject = new MyClass();

                string someString = myobject.GetSomeString(myMock.Object);

                Assert.AreEqual(EXPECTED_STRING, someString);
                myMock.VerifyAll();

            }

        }

        public class MyClass
        {

            public virtual string GetSomeString(IDependance objectThatITalkTo)
            {
                return objectThatITalkTo.GiveMeAString();
            }
        }

        public interface IDependance
        {
            string GiveMeAString();
        }
    }

コードが背後にロジックを持たない文字列を返すだけの場合、何か有用なことをしているようには見えません。

GetSomeString()からの戻り値に応じて出力文字列の結果を変更する可能性のあるロジックをメソッドで実行すると、真の力が発揮されIDependdance ます。GiveMeAString()メソッドを使用すると、インターフェイスから送信された不正なデータをメソッドがどのように処理するかを確認できIDependdanceます。

何かのようなもの:

 public virtual string GetSomeString(IDependance objectThatITalkTo)
 {
     if (objectThatITalkTo.GiveMeAString() == "Hello World")
         return "Hi";
     return null;
 }

テストに次の行がある場合:

myMock.Expect(m => m.GiveMeAString()).Returns(null);

あなたのGetSomeString()方法はどうなりますか?

于 2008-12-03T05:41:45.527 に答える
9

大きな間違いは、テスト対象のシステム(SUT) をモックすることです。別のものをテストします。SUT の依存関係のみをモックする必要があります。

于 2008-12-03T05:26:37.163 に答える
3

ここで行われている相互作用を理解するまで、フレームワークのモックには近づかないことをお勧めします。

IMO 手動で作成されたテスト ダブルで学習し、その後、モック フレームワークに移行することをお勧めします。私の推論:

  1. モッキング フレームワークは、実際に何が起こっているかを抽象化します。依存関係を明示的に作成し、デバッガーでテストに従う必要がある場合は、相互作用を把握するのが簡単です。

  2. フレームワークを誤用するのは簡単です。学習中に自分で転がすと、さまざまなタイプのテストダブルの違いを理解する可能性が高くなります。モック フレームワークに直行すると、スタブが必要なときにモックを使用するのは簡単であり、その逆も同様です。大きな違いがあります。

このように考えてみてください。テスト対象のクラスが焦点です。そのインスタンスを作成し、そのメソッドを呼び出して、結果が正しいことをアサートします。テスト対象のクラスに依存関係がある場合 (たとえば、コンストラクターで何かが必要な場合)、A: 実際のクラスまたは B: テスト ダブルのいずれかを使用して、それらの依存関係を満たします。

テスト ダブルを使用する理由は、テスト対象のクラスを分離するためです。つまり、より制御された方法でそのコードを実行できるということです。

たとえば、ネットワーク オブジェクトを含むクラスがある場合、具体的なネットワーク接続オブジェクトを使用せざるを得ない場合、所有しているクラスのエラー処理ルーチンをテストして、切断された接続を検出することはできません。代わりに、偽の接続オブジェクトを挿入し、その「SendBytes」メソッドが呼び出されたときに例外をスローするように指示します。

つまり、各テストでは、テスト対象のクラスの依存関係が、特定のコードを実行するために特別に作成されます。

于 2009-06-06T02:23:44.473 に答える