3

I have the following test code.

var test = "Test";

var command = new MyCommand { V = test };

var mock = new Mock<IRepository>(); // IRepository has the method of Save()
var p = new P(test);
mock.Setup(x => x.Save(p)).Verifiable();

var sut = new C(mock.Object);
var result = await sut.M(command);

mock.Verify();

The test should pass. However, it failed with the error of,

  Message: 
    Moq.MockException : Mock:
    This mock failed verification due to the following:

       IRepository x => x.Save(P):
       This setup was not matched.
  Stack Trace: 
    Mock.Verify()

sut.M() will convert a string X to type P with value of P(X).

ca9163d9
  • 27,283
  • 64
  • 210
  • 413
  • 5
    Try `mock.Setup(x => x.Save(It.IsAny

    ()))` otherwise it expects the exact same `P` to be passed and I doubt `P` has value equality setup.

    – juharr Dec 19 '19 at 22:28
  • I don't see anywhere that `p` is being used outside of `x.Save(p)`. @juharr's point is what I was getting at. – Matt U Dec 19 '19 at 22:28
  • BTW, can Moq verify a method is not called? – ca9163d9 Dec 19 '19 at 22:38
  • 2
    Yes, you can do something like `mock.Verify(x => x.Save(It.IsAny

    (), Times.Never));`. Other options include `Once`, `AtLeastOnce`, and others that specify a specific number of times or range of times it can be called.

    – juharr Dec 19 '19 at 22:40
  • 2
    You can also use `Callback` to get the arguments so you can test that it did pass a `P` with the `test` value like `mock.Setup(x => x.Save(It.IsAny

    ())).Callback

    (p => Assert.Equal(p.Whaterver, test))`

    – juharr Dec 19 '19 at 22:45
  • @juharr, I can compare exactly the value of P when using callback? so i don't need to use `It.IsAny

    `?

    – ca9163d9 Dec 19 '19 at 22:48
  • @juharr, unfortunately, The Assert in the `Callback` is not called. I set a break point in it and it was not hit. – ca9163d9 Dec 19 '19 at 23:22

1 Answers1

5

It seems to me that you want to verify that the Save method from your mock is called with a specific value, and not just a type.

I have tried something like the following and believe it should work. I have modified your example.

var test = "Test";

var command = new MyCommand { V = test };

var mock = new Mock<IRepository>(); // IRepository has the method of Save()
var p = new P(test);
mock.Setup(x => x.Save(It.IsAny<P>());

var sut = new C(mock.Object);
var result = await sut.M(command);

mock.Verify(x => x.Save(It.Is<P>(v => v.Value.Equals(p.Value))), Times.AtLeastOnce);

This tests that the values of the specific property are equal.

I Tested this with the following test:

var test = "Test";

var mock = new Mock<ITestRepository>(); // ITestRepository has the method of Save()
var p = new P(test);
mock.Setup(x => x.Save(It.IsAny<P>()));

mock.Object.Save(new P(test));

mock.Verify(x => x.Save(It.Is<P>(v => v.Value.Equals(p.Value))), Times.AtLeastOnce);
Soenderby
  • 157
  • 1
  • 11
  • BTW, I found it also works even I didn't call `.Verifiable()`? For example, `_repositoryMock.Verify(x => x.Add(It.IsAny()), Times.Once)` works without it. – ca9163d9 Dec 20 '19 at 17:40
  • Yes @ca9163d9 it would seem that this is considered the better way of verifying. You can learn more by reading [this question](https://stackoverflow.com/questions/980554/what-is-the-purpose-of-verifiable-in-moq). I Have edited my answer to use this approach instead. – Soenderby Dec 20 '19 at 20:58
  • Just found it works after commenting out `mock.Setup(x => x.Save(It.IsAny

    ());`. Is it still necessary with the updated `Verify(x => ...)`?

    – ca9163d9 Dec 20 '19 at 22:01
  • I don't think the setup is necessary as long as none of the code you are testing relies on what `Save` returns or any other side effects. And i think you should keep the updated `Verify` if you want to test the method is called with a certain value. – Soenderby Dec 20 '19 at 23:39
  • Yes, I use the updated version now. It's clearer for the intension and the second parameter of `Times` is useful. Thanks. – ca9163d9 Dec 21 '19 at 03:26