Moq and Entity Framework Core do not really work with asynchronous methods?

.net-core c# entity-framework-core mocking moq

Question

I'm trying to create a test repository using Moq with EF Core, using its asynchronous methods (like AddAsync and SaveChangesAsync), but I have not had the slightest success ...

I've found many and many blog posts (including questions here), but nothing works for me.

For example, I literally copied the code from this article and tried to implement its references: [https://fpnotebook.wordpress.com/2017/05/29/asp-net-core-testing-repositories-and-mocking-ef /] but the problem is always the same, for example:

Message: Moq.MockException:
Expected invocation on the mock once, but was 0 times: m => m.AddAsync (It.IsAny (),)
No setups configured.

And the same goes for SaveChangesAsync.

Here's an example code I've been trying to implement:

//The configuration

dbSetMock.Setup(m => m.AddAsync(It.IsAny<T>), It.IsAny<CancellationToken>()))
    .Callback ((T model, CancellationToken token) => {queryableList.Concat (new [] {model})}})
    .Returns ((T model, CancellationToken token) => Task.FromResult((EntityEntry<T>) null));

// The test itself

[Fact]
public async void AddAsyncTest ()
{
    var mockSet = new Mock <DbSet <Wine >> ();

    var mockContext = new Mock <SQLContext> (_ options);
    mockContext.Setup (m => m.Set <Wine> ()). Returns (mockSet.Object);

    var service = new WineCommandRepository (mockContext.Object);
    await service.Insert (new Wine
    {
        IdWine = 1,
        Name = "Wine1"
    });
    mockContext.Object.SaveChanges ();

    mockSet.Verify (m => m.AddAsync (It.IsAny <Wine>), 
        new CancellationToken ()), Times.Once ());

    mockContext.Verify (m => m.SaveChanges (), Times.Once ());
}

There is nothing extraordinary about my code, I have used what I have always used for synchronous repository but this case is new to me.

Has anyone overcome this and have some example or recommendation to share?

1
0
4/24/2018 6:49:50 PM

Popular Answer

I suspect the reason this isn't working is that this check (for which I have added missing brackets from the question and removed unnecessary brackets) will never pass:

mockSet.Verify(m => m.AddAsync(It.IsAny<Wine>()), new CancellationToken()), Times.Once);

The reason is that Verify is checking that the method was called with the supplied parameters, not something 'equivalent', but exactly what you told it (reference equals). However, the Verify is being given a new instance of a CancellationToken, and there is no possible way that the code under test will be returning that exact instance of a CancellationToken.

Either you need to use It.IsAny<CancellationToken>(), or if you abstract your code under test away from explicitly using new CancellationToken(), and supply that via the test setup, then you could supply that specific instance to Verify.

While I'm here, I should offer a caution about using It.IsAny in case you don't know. Take a look at this question's not accepted answer and comments, then the accepted answer.

1
4/29/2018 10:30:22 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow