A collection of learnings and opinions.

Friday, September 25, 2009

MoQ with Collections, or equality woes

Still working with the fine mocking-framework MoQ, I came across a somewhat surprising facet (and I don't like surprises).
I'm mocking out a class which should be added to a collection after a method-call, like so:

public class SomeClass{

}

public class Container {
private List<SomeClass>; classes = new List<SomeClass>();

public IEnumerable<SomeClass> Classes {
get {
return classes;
}
}

public void addSomeClass(SomeClass instance) {
classes.Add(instance);
}
}

[Test]
public void ContainerContainsAddedClassAfterAdd() {
var mockSomeClass = new Mock<SomeClass>();
mockSomeClass.Setup(c => c.Equals(mockSomeClass.Object)).Return(true);

var Container = new Container();
Container.addSomeClass(mockSomeClass.Object);

Assert(Container.Classes.Contains(mockSomeClass.Object));
}

This works well, the mock is added to the Container's collection and the setup of the Equals method on the mock makes sure the IEnumerable.Contains() return true.
However there's always some complication. The class I'm really mocking out is not as simple as our SomeClass. It's something like this:

public class SomeClassOverridingEquals{
public virtual Equals(SomeClassOverridingEquals other) {
return false;
}

public override Equals(object obj) {
var other = obj as SomeClassOverridingEquals;

if (other != null) return Equals(other); // calls the override
return false;
}
}

[Test]
public void ContainerContainsAddedClassOverridingEqualsAfterAdd() {
var mockSomeClass = new Mock<SomeClassOverridingEquals>();
mockSomeClass.Setup(c => c.Equals(mockSomeClass.Object)).Return(true);

var Container = new Container();
Container.addSomeClass(mockSomeClass.Object);

Assert(Container.Classes.Contains(mockSomeClass.Object)); // fails
}

The class contains an override for the Equals method for its own specific type, and the Setup method for the mock does not seem to be able to mock out that specific method (only overriding the more general Equals(object)). Thus the test fails.

I have so far found no way of working around this quite common pattern, other than rewriting the class not to use the overriding equals.

I don't like that.

Anyone have any ideas?

No comments: