Joel Min
Joel Min

Reputation: 3457

Exception of invocation on the mock was 0 times, but I can see performed invocations correctly

Here's my simplified version of unit test

var service = Fixture.Freeze<IService>();
var outerService = Fixture.Create<OuterService>();

var testObject = Fixture.Create<TestObject>();

outerService.Notify(testObject);
Mock.Get(service).Verify(s => s.SendNotification(It.IsAny<String>(), It.IsAny<TestObject>(), null), Times.Once);

Note that:

outerService.Notify(testObject)

internally calls

IService.SendNotification(string testObject.Name, testObject, extraObject = null)


The above will cause the test to fail, complaining that:

Expected invocation 1 time,but was 0 times: 
s => s.SendNotification(It.IsAny<String>(), It.IsAny<TestObject>(), null)
No setups configured.

Performed invocations:
IService.SendNotification("testObject", UnitTest.TestObject, null)

I don't understand, the performed invocation looks exactly like the expected invocation, what is going on here?


EDIT

Ok so it is working if I call service.SendNotification directly in the test, but it won't work if I call it via outerService? Why?


UPDATE

Apologies if my question was not clear enough, here's some more details as to how the Fixture object is configured:

Fixture fixture = new Fixture();
fixture.Customize(new AutoConfiguredMoqCustomization());
fixture.Customize(new SpecimenCustomization());

That is really about it for the details, it's hopefully not a complicated scenario I suppose.

Upvotes: 2

Views: 460

Answers (1)

Nkosi
Nkosi

Reputation: 247571

That error occurs when you call Mock.Get and The received mocked instance was not created by Moq. That means that there were No setups configured for the mocked service.

Given this simplified assumption.

public class OuterService {
    private IService service;

    public OuterService(IService service) {
        this.service = service;
    }

    public void Notify(TestObject testObject) {
        service.SendNotification(testObject.Name, testObject, extraObject: null);
    }
}

public interface IService {
    void SendNotification(string name, TestObject testObject, object extraObject);
}

public class TestObject {
    public string Name { get; set; }
} 

The following test should work

//Arrange
var service = Mock.Of<IService>();
var outerService = new OuterService(service);
var testObject = new TestObject { Name = "testObject" };

//Act
outerService.Notify(testObject);

//Assert
Mock.Get(service).Verify(s => s.SendNotification(It.IsAny<String>(), It.IsAny<TestObject>(), null), Times.Once);

Moq is now aware of the service object and can extract the mock setup from the mocked instance created above.

Update:

Realized you were using AutoFixture and after some research was able to recreate your problem. You need to customize AutoFixture to use Moq.

Check Auto-Mocking with Moq on how to do that.

The following then worked given the same assumptions stated above.

//Arrange
var fixture = new Fixture();
fixture.Customize(new Ploeh.AutoFixture.AutoMoq.AutoMoqCustomization());

var service = fixture.Freeze<IService>();
var outerService = fixture.Create<OuterService>();
var testObject = fixture.Create<TestObject>();

//Act
outerService.Notify(testObject);

//Assert
Mock.Get(service).Verify(s => s.SendNotification(It.IsAny<String>(), It.IsAny<TestObject>(), null), Times.Once);

Upvotes: 1

Related Questions