Today I changed to use StringDictionary
instead of Dictionary<string,string>
in my code, but old unit test failed. So I write a small unit test to test this.
Here is my small test:
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();
}
}
}
If I use Dictionary<string,string>
, the test will pass, but when I use StringDictionary
, the test failed.
What's the problem here?
Problem goes from StringDictionary
instances comparison. There is no overridden Equals
method, thus instances compared not by content, but by references. If you will use same instance, test will pass:
[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();
}
You can override Equals
on your CustomDictionary
class to make your original test pass:
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;
}
BTW I hope this is not your real test, because here you are testing mock, instead of testing your code.
WHY YOUR CODE WORKS WITH DICTIONARY:
As I understand RhinoMocks implementation, Rhino.Mocks.Impl.Validate
class used for arguments validation. You can take a look on it's ArgsEqual
method implementation:
public static bool ArgsEqual(object[] expectedArgs, object[] actualArgs)
{
return RecursiveCollectionEqual(expectedArgs, actualArgs);
}
I leave to you details of RecursiveCollectionEqual
, but interesting part there is arguments comparison:
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;
}
As you can see, if argument is ICollection
then Rhino goes deeper to compare expected and actual collections. Dictionary
implements ICollection
, but StringDictionary
does not. Thus arguments of StringDictionary
types compared only by reference.
UPDATE: Didn't notice, that you have an alias. Just inherit from type instead, and you will be able to override Equals
:
public class CustomDictionary : StringDictionary