1

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?

Sebastien
  • 1,308
  • 2
  • 15
  • 39
  • It is trying to compare different value class that in method under test. use `It.Any()`. you could also apply a predicate if you want to compare the fields/properties if they are exposed. – Nkosi Jan 17 '17 at 15:20

1 Answers1

1

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.
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • 1
    I just overrode (override, overriden?) the Equals() and GetHashCode() for ValueClass. Test is now passing! Thanks! – Sebastien Jan 17 '17 at 15:28
  • Didn't know you could add predicate! I guess I will use the predicates instead because I'll have to add tests for the Equals() and I would rather not have to. – Sebastien Jan 17 '17 at 15:40
  • 1
    @Sebastien you can, but keep in mind redability of your tests. They can become very cluttered. Also imagine - you have 50 tests which check values in predicate. And then you add new field to ValueClass. With Equals you just change overload. With predicate you have to update 50 tests. – Sergey Berezovskiy Jan 17 '17 at 15:45
  • Ooohhh... derpyderp! Equals it is XD! I don't want to break my test every time the ValueClass changes! – Sebastien Jan 17 '17 at 15:51