Search code examples
c#unit-testingnunitmoqncrunch

C# Nunit Moq Cannot make test pass


I have this class:

class MyClass
{
    private ISomeInterface blabla;

    public MyClass() : this(new SomeInterfaceImplementation()) {}

    internal MyClass(ISomeInterface blabla)
    {
        this.blabla = blabla;
    }

    public void SomeMethod(string id, int value1, int value2)
    {
        this.blabla.DoSomethingWith(id, new ValueClass(value1, value2))
    }
}

I also have this test:

[TestFixture]
public class MyClassTest
{
    private const string ID = "id";
    private const int VALUE1 = 1;
    private const int VALUE2 = 2;

    private ValueClass valueClass;

    private Mock<ISomeInterface> mockInterface;

    private MyClass myClass;

    [SetUp]
    public void SetUp()
    {
        this.valueClass = new ValueClass(VALUE1, VALUE2);
        this.mockInterface = new Mock<ISomeInterface>();
        this.myClass = new MyClass(this.mockInterface.Object);
    }

    [Test]
    public void GIVEN_AnID_AND_AValue1_AND_AValue2_WHEN_DoingSomeMethod_THEN_TheSomeInterfaceShouldDoSomething()
    {
        this.myClass.SomeMethod(ID, VALUE1, VALUE2);
        this.mockInterface.Verify(m => m.DoSomethingWith(ID, this.valueClass), Times.Once()); //<- Test fails here!
    }
}

I don't know why but I can't get this test to pass. NCrunch is giving me the following error message:

Moq.MockException : Expected invocation on the mock once, but was 0 times: m => m.DoSomethingWith("ID", .valueClass) No setups configured.

Performed invocations:

ISomeInterface.DoSomethingWith("ID", MyNamespace.ValueClass) at Moq.Mock.ThrowVerifyException(MethodCall expected, IEnumerable1 setups, IEnumerable1 actualCalls, Expression expression, Times times, Int32 callCount) at Moq.Mock.VerifyCalls(Interceptor targetInterceptor, MethodCall expected, Expression expression, Times times) at Moq.Mock.Verify[T](Mock1 mock, Expression1 expression, Times times, String failMessage) at Moq.Mock1.Verify(Expression1 expression, Times times) at Tests.MyClassTest.GIVEN_AnID_AND_AValue1_AND_AValue2_WHEN_DoingSomeMethod_THEN_TheSomeInterfaceShouldDoSomething() in C:\MySourceCode\File and line number here.

As you can see, it seems like Moq is "not seeing" my invocation, probably because of the new ValueClass(value1, value2) how can I make this test pass or how can I change my design so it is easier to test? Where should I put the new ValueClass(value1, value2)?

EDIT:

Is this a question I should ask on Software Engineering instead of StackOverflow? Is this out of scope?


Solution

  • Your problem is not matching argument in method call: this.valueClass by default is not equal to new ValueClass(value1, value2) because it will be two different instances of ValueClass. And by default two instances will be compared by references, which are different. You can:

    • Override Equals and GetHashCode methods in ValueClass to change the way how two instances compared. I.e. compare by values instead of comparing by references.
    • Ignore this argument with It.Any<ValueClass>(). It's good if you don't care about specific values of ValueClass and just want to check method was called. Not always best option
    • Use predicate to check values of ValueClass manually: It.Is<ValueClass>(vc => vc.Value1 == VALUE1 && vc.Value2 == VALUE2). Sometimes it's also good. E.g. if you cannot override Equals. But it makes tests much less readable.