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;
}

如您所见,如果参数是,ICollection则 Rhino 会更深入地比较预期和实际集合。Dictionary实现ICollection,但StringDictionary没有。因此,StringDictionary类型的参数仅通过引用进行比较。

更新:没有注意到,你有一个别名。只需从 type 继承,您就可以覆盖Equals

public class CustomDictionary : StringDictionary
于 2012-07-19T07:06:02.260 回答
0

我不知道这是否有帮助,但两者之间的主要区别在于 StringDictionairy 会自动将所有键小写(测试变为测试)。也许这就是测试失败的原因?

于 2012-07-19T06:25:44.917 回答
0

问题是 Rhino Mocks 在检查 Expect.Call() 中传递的参数是否与实际传递的参数匹配时通过引用进行比较。
您的代码中的问题是您创建了 2 个不同的自定义字典对象,一个用于期望,一个用于实际调用,因此它们不匹配:

        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 回答