C#如何Moq实体框架DbSet添加方法

Muk*_*thi 0 c# unit-testing moq entity-framework-4 c#-4.0

我正在尝试创建一个测试以测试实体框架Add方法。任何人都可以帮助模拟该DbSet.Add方法。我已经尝试了如下但不能正常工作。我究竟做错了什么?

我得到的结果是nullrepository.Insert... 之后

Test.cs:

var productToCreate = new Product { Name = "Added", Description = "Added" };        

var result = repository.InsertAsync(objToCreate, userContext).Result;
Assert.AreEqual(result.Name, "Added");  
Run Code Online (Sandbox Code Playgroud)

Mock.cs

internal static DbSet<T> GetMockedDataSet<T>(IEnumerable<T> data) where T : class
{
    // Create a mocked data set that contains the data
    var set = new Mock<DbSet<T>>();
    set.As<IDbAsyncEnumerable<T>>()
        .Setup(m => m.GetAsyncEnumerator())
        .Returns(new TestDbAsyncEnumerator<T>(data.GetEnumerator()));
    set.As<IQueryable<T>>()
        .Setup(m => m.Provider)
        .Returns(new TestDbAsyncQueryProvider<T>(data.AsQueryable().Provider));
    set.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.AsQueryable().Expression);
    set.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.AsQueryable().ElementType);
    set.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

    set.Setup(x => x.AsNoTracking()).Returns(set.Object);
    set.Setup(x => x.Add(It.IsAny<T>())).Callback<T>((s) => data.Concat(new[] { s }));

    // Return the mock
    return set.Object;
}
Run Code Online (Sandbox Code Playgroud)

仓库:

public async Task<Product> InsertAsync(Product input)
{
    using (var ctx = .....))
    {
        var added = ctx.Set<Product>().Add(input);

        await ctx.ValidateAndSaveAsync();

        return added;
    }
}
Run Code Online (Sandbox Code Playgroud)

Nko*_*osi 5

根据Add该方法在被测方法中的使用方式...

var added = ctx.Set<Product>().Add(input);
Run Code Online (Sandbox Code Playgroud)

... Returns如果需要的功能,则安装程序中还应该有一个返回输入参数的。

set.Setup(x => x.Add(It.IsAny<T>()))
   .Returns<T>(arg => arg)
   .Callback<T>((s) => data.Concat(new[] { s }));
Run Code Online (Sandbox Code Playgroud)

但是鉴于有关上下文依赖的信息是未知的...

using (var ctx = .....))
Run Code Online (Sandbox Code Playgroud)

不确定所提供的解决方案是否会达到预期的效果。

另外,如果测试异步方法,请不要混合使用异步和同步调用。下一行...

var result = repository.InsertAsync(objToCreate, userContext).Result;
Run Code Online (Sandbox Code Playgroud)

...可能会导致死锁。

使测试方法一直保持异步。

[TestMethod]
public async Task InsertAsync_Should_Return_Product() {
    //...other code

    var expected = new Product { Name = "Added", Description = "Added" };        

    var actual = await repository.InsertAsync(expected, userContext);

    Assert.AreEqual(expected.Name, actual.Name);  
}
Run Code Online (Sandbox Code Playgroud)