I'm trying to mock a mapping interface IMapper
:
public interface IMapper<TFoo, TBar> {
TBar Map(TFoo foo);
TFoo Map(TBar bar);
}
In my test, I'm setting the mock mapper up to expect an invocation of each (around an NHibernate update
operation):
//...
_mapperMock.Setup(m => m.Map(fooMock.Object)).Returns(barMock.Object);
_mapperMock.Setup(m => m.Map(barMock.Object)).Returns(fooMock.Object);
//...
However, when the second Map
invocation is made, the mapper mock throws because it is only expecting a single invocation.
Watching the mapper mock during setup at runtime, I can look see the Map(TFoo foo)
overload get registered, and then see it get replaced when the Map(TBar bar)
overload is set up.
Is this a problem with the way Moq handles setup, or is there a different syntax I need to use in this case?
EDIT Here is the actual instantiation code from the test constructor:
public class TestClass {
private readonly MockRepository _repository = new MockRepository(MockBehavior.Strict);
public TestClass() {
//...
_mapperMock = _repository.Create
<IMapper<RequestData.Foo, ResponseData.Bar>>();
//...
}
}
EDIT 2
Here is a complete failing test case:
public interface IMapper<TFoo, TBar> {
TFoo Map(TBar bar);
TBar Map(TFoo foo);
}
public class Foo {
public override int GetHashCode() {
// return base.GetHashCode();
return 1;
}
}
public class Bar {
public override int GetHashCode() {
// return base.GetHashCode();
return 2;
}
}
[Test]
public void TestIt()
{
// Arrange
var _mapperMock = new Mock<IMapper<Foo, Bar>>(MockBehavior.Strict);
var fooMock = new Mock<Foo>();
var barMock = new Mock<Bar>();
_mapperMock.Setup(m => m.Map(fooMock.Object)).Returns(barMock.Object);
_mapperMock.Setup(m => m.Map(barMock.Object)).Returns(fooMock.Object);
// Act - breaks on first line below this comment
var bar = _mapperMock.Object.Map(fooMock.Object);
var foo = _mapperMock.Object.Map(barMock.Object);
// Assert
_mapperMock.Verify(x => x.Map(fooMock.Object), Times.Once());
_mapperMock.Verify(x => x.Map(barMock.Object), Times.Once());
}
If I comment out the GetHashCode()
override on either Foo
or Bar
, or on both, the test case passes. Or, if I don't use Mock
s of Foo
and Bar
, the test case passes.
EDIT 3 I opened Moq Issue 347 against this problem, with more detailed test cases.
Not sure what your Foo
and Bar
classes look like, but this test passes for me (Moq 4.0.10827.0, which is the newest one in NuGet)
using Moq;
using NUnit.Framework;
namespace ConsoleApplication1
{
[TestFixture]
public class Tests
{
[Test]
public void TestIt()
{
// Arrange
var _mapperMock = new Mock<IMapper<Foo, Bar>>();
var fooMock = new Mock<Foo>();
var barMock = new Mock<Bar>();
_mapperMock.Setup(m => m.Map(fooMock.Object)).Returns(barMock.Object);
_mapperMock.Setup(m => m.Map(barMock.Object)).Returns(fooMock.Object);
// Act
var bar = _mapperMock.Object.Map(fooMock.Object);
var foo = _mapperMock.Object.Map(barMock.Object);
// Assert
Assert.AreSame(bar, barMock.Object);
Assert.AreSame(foo, fooMock.Object);
_mapperMock.Verify(x => x.Map(fooMock.Object), Times.Once());
_mapperMock.Verify(x => x.Map(barMock.Object), Times.Once());
}
}
public class Bar
{
}
public class Foo
{
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With