1

今日、コードStringDictionaryの代わりに使用するように変更しましDictionary<string,string>たが、古い単体テストは失敗しました。そこで、これをテストするための小さな単体テストを作成します。

これが私の小さなテストです:

using Rhino.Mocks;
using NUnit.Framework;
//using CustomDictionary = System.Collections.Specialized.StringDictionary;
using CustomDictionary = System.Collections.Generic.Dictionary<string, string>;

namespace ConsoleApplication1
{
    public interface ITest
    {
        void DoSth(CustomDictionary dic);
    }
    public class OneTest : ITest
    {
        public void DoSth(CustomDictionary dic) {/*do nothing*/}
    }

    [TestFixture]
    public class TestClass
    {
        [Test]
        public void Test1()
        {
            var mockRepository = new MockRepository();
            var test = mockRepository.StrictMock<ITest>();

            using (mockRepository.Record())
            {
                Expect.Call(() => test.DoSth(new CustomDictionary { { "Test", "Test1" } }));
            }
            test.DoSth(new CustomDictionary { { "Test", "Test1" } });

            mockRepository.VerifyAll();
        }
    }
}

を使用するDictionary<string,string>とテストに合格しますが、を使用するStringDictionaryとテストに失敗します。

ここでの問題は何ですか?

4

3 に答える 3

1

問題はStringDictionaryインスタンスの比較にあります。オーバーライドさEqualsれたメソッドがないため、インスタンスは内容ではなく参照によって比較されます。同じインスタンスを使用する場合、テストはパスします:

    [Test]
    public void Test1()
    {
        var mockRepository = new MockRepository();
        var test = mockRepository.StrictMock<ITest>();
        var dictionary = new CustomDictionary { { "Test", "Test1" } };

        using (mockRepository.Record())            
            Expect.Call(() => test.DoSth(dictionary));

        test.DoSth(dictionary);
        mockRepository.VerifyAll();
    }

クラスをオーバーライドEqualsして、元のテストに合格することができます。CustomDictionary

public override bool Equals(object obj)
{
    CustomDictionary other = obj as CustomDictionary;
    if (other == null)
        return false;

    if (Count != other.Count)
        return false;

    foreach (string key in Keys)
    {
        if (!other.ContainsKey(key))
            return false;

        if (this[key] != other[key])
            return false;
    }

    foreach (string key in other.Keys)
    {
        if (!ContainsKey(key))
            return false;
    }

    return true;
}

ところで、これが実際のテストではないことを願っています。ここでは、コードをテストするのではなく、モックをテストしているためです。

コードが辞書で機能する理由:

RhinoMocks の実装を理解しているのでRhino.Mocks.Impl.Validate、引数の検証に使用されるクラスです。ArgsEqualメソッドの実装を確認できます。

public static bool ArgsEqual(object[] expectedArgs, object[] actualArgs)
{
    return RecursiveCollectionEqual(expectedArgs, actualArgs);
}

の詳細はお任せしますRecursiveCollectionEqualが、興味深いのは引数の比較です。

if (current == null)
{
    if (actual != null)
        return false;
}
else if (!SafeEquals(current, actual))
{
    if (current is ICollection)
    {
        if (!RecursiveCollectionEqual((ICollection)current, (ICollection)actual))
            return false;

        continue;
    }
    return false;
}

ご覧のとおり、argument が の場合ICollection、Rhino は予想されるコレクションと実際のコレクションをさらに詳しく比較します。Dictionaryを実装していますICollectionが、実装していStringDictionaryません。したがって、型の引数はStringDictionary参照によってのみ比較されます。

更新: エイリアスがあることに気づきませんでした。代わりに型から継承するだけで、オーバーライドできるようになりますEquals:

public class CustomDictionary : StringDictionary
于 2012-07-19T07:06:02.260 に答える
0

これが役立つかどうかはわかりませんが、2つの主な違いは、StringDictionairyがすべてのキーを自動的に小文字にすることです(テストがテストになります)。たぶんそれがテストが失敗する理由ですか?

于 2012-07-19T06:25:44.917 に答える
0

問題は、Expect.Call() で渡されたパラメーターが実際に渡されたパラメーターと一致するかどうかをチェックするときに、Rhino Mocksが参照によって比較することです。
コードの問題は、カスタム辞書の 2 つの異なるオブジェクトを作成することです。1 つは期待用で、もう 1 つは実際の呼び出し用です。したがって、それらは一致しません。

        using (mockRepository.Record())
        {
            Expect.Call(() => test.DoSth(new CustomDictionary { { "Test", "Test1" } }));
        }
        test.DoSth(new CustomDictionary { { "Test", "Test1" } });

次のように簡単に修正できます(重複も削除されます)。

        var myDictionary = new CustomDictionary { { "Test", "Test1" } }));
        using (mockRepository.Record())
        {
            Expect.Call(() => test.DoSth(myDictionary);
        }
        test.DoSth(myDictionary );
于 2012-07-19T10:14:59.697 に答える