Moq和Entity Framework Core实际上不适用于异步方法吗?

时间:2018-04-24 18:28:03

标签: c# mocking .net-core entity-framework-core moq

我正在尝试使用Moq和EF Core创建一个测试存储库,使用其异步方法(如AddAsyncSaveChangesAsync),但我没有取得丝毫成功......

我发现了很多很多博客文章(包括这里的问题),但对我来说没什么用。

例如,我从字面上复制了本文中的代码并尝试实现其引用:[https://fpnotebook.wordpress.com/2017/05/29/asp-net-core-testing-repositories-and-mocking-ef /]但问题始终相同,例如:

  

消息:Moq.MockException:
  在模拟上预期调用一次,但是是0次:m => m.AddAsync(It.IsAny(),)
  没有配置设置。

同样适用于SaveChangesAsync

这是我一直试图实现的示例代码:

//配置

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));

//测试本身

[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 ());
}

我的代码没有什么特别之处,我使用了我一直用于同步存储库的东西,但这种情况对我来说是新的。

有没有人克服这个并有一些例子或建议分享?

1 个答案:

答案 0 :(得分:1)

我怀疑这不起作用的原因是这个检查(我在问题中添加了缺失括号并删除了不必要的括号)将永远不会通过:

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

原因是Verify正在检查方法是使用提供的参数调用的,而不是“等效”的,但正是你告诉它的(引用等于)。但是,Verify被赋予了一个CancellationToken的新实例,并且没有可能的方式被测试的代码将返回CancellationToken的确切实例。

您需要使用It.IsAny<CancellationToken>(),或者如果您将测试中的代码抽象而不是显式使用new CancellationToken(),并通过测试设置提供,那么您可以将该特定实例提供给{{ 1}}。

虽然我在这里,但如果您不知道,我应该谨慎使用Verify。看看this question未接受的答案和评论,然后是接受的答案。