简体   繁体   中英

C# How to Moq entityframework DbSet Add method

I am trying to create a test to test entity framework Add method. Can anyone help how to mock the DbSet.Add method. I have tried as below but not working. What am I doing wrong?

The result I am getting is null after repository.Insert ...

Test.cs:

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

var result = repository.InsertAsync(objToCreate, userContext).Result;
Assert.AreEqual(result.Name, "Added");  

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

Repository:

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

        await ctx.ValidateAndSaveAsync();

        return added;
    }
}

According to how the Add method is being used in the method under test...

var added = ctx.Set<Product>().Add(input);

...there should also be a Returns in the setup that returns the argument that was entered, if that is the desired functionality.

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

But given that the information about context dependency is unknown...

using (var ctx = .....))

It is uncertain if the provided solution will have the desired effect.

Additionally if testing an async method, don't mix async and sync calls. The following line...

var result = repository.InsertAsync(objToCreate, userContext).Result;

...can cause deadlocks.

Make the test method async all the way.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM