模拟AsNoTrackingentity framework

我如何模拟AsNoTracking方法?
在下面的示例中,DbContext已注入服务类。如果我从GetOrderedProducts方法中删除AsNoTracking扩展方法,但是AsNoTracking测试失败,因为它返回null,它工作正常。 我也尝试过模拟AsNoTracking来返回正确的值,但它没有用。

public interface IUnitOfWork { IDbSet Set() where TEntity : class; int SaveAllChanges(); } public class Entites : DbContext, IUnitOfWork { public virtual DbSet Products { get; set; } // This is virtual because Moq needs to override the behaviour public new virtual IDbSet Set() where TEntity : class // This is virtual because Moq needs to override the behaviour { return base.Set(); } public int SaveAllChanges() { return base.SaveChanges(); } } public class ProductService { private readonly IDbSet _products; private readonly IUnitOfWork _uow; public ProductService(IUnitOfWork uow) { _uow = uow; _products = _uow.Set(); } public IEnumerable GetOrderedProducts() { return _products.AsNoTracking().OrderBy(x => x.Name).ToList(); } } [TestFixture] public class ProductServiceTest { private readonly ProductService _productService; public ProductServiceTest() { IQueryable data = GetRoadNetworks().AsQueryable(); var mockSet = new Mock<DbSet>(); mockSet.As<IQueryable>().Setup(m => m.Provider).Returns(data.Provider); mockSet.As<IQueryable>().Setup(m => m.Expression).Returns(data.Expression); mockSet.As<IQueryable>().Setup(m => m.ElementType).Returns(data.ElementType); mockSet.As<IQueryable>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator()); var context = new Mock(); context.Setup(c => c.Products).Returns(mockSet.Object); context.Setup(m => m.Set()).Returns(mockSet.Object); context.Setup(c => c.Products.AsNoTracking()).Returns(mockSet.Object); _productService = new ProductService(context.Object); } private IEnumerable GetRoadNetworks() { return new List { new Product { Id = 1, Name = "A" }, new Product { Id = 2, Name = "B" }, new Product { Id = 1, Name = "C" } }; } [Test] public void GetOrderedProductTest() { IEnumerable products = _productService.GetOrderedProducts(); List names = products.Select(x => x.Name).ToList(); var expected = new List {"A", "B", "C"}; CollectionAssert.AreEqual(names, expected); } } 

问题是AsNoTracking在unit testing中返回null 在此处输入图像描述

查看AsNoTracking()扩展方法的源代码 :

 public static IQueryable AsNoTracking(this IQueryable source) { var asDbQuery = source as DbQuery; return asDbQuery != null ? asDbQuery.AsNoTracking() : CommonAsNoTracking(source); } 

由于source (您尝试模拟的DbSet )确实是DbQuery (因为DbSet派生自DbQuery ),它会尝试调用正确返回null的“真实”(非模拟) AsNoTracking()方法。

尝试模拟AsNoTracking()方法:

 mockSet.Setup(x => x.AsNoTracking()).Returns(mockSet.Object); 

你有:

 context.Setup(c => c.Products).Returns(mockSet.Object); context.Setup(m => m.Set()).Returns(mockSet.Object); context.Setup(c => c.Products.AsNoTracking()).Returns(mockSet.Object); 

但请记住,扩展方法只是语法糖。 所以:

 c.Products.AsNoTracking() 

真的只是:

 System.Data.Entity.DbExtensions.AsNoTracking(c.Products) 

因此,上面的模拟设置毫无意义。

问题是静态DbExtensions.AsNoTracking(source)方法实际上对其参数做了什么。 另见线程有什么区别.AsNoTracking()会做什么?

如果您只是从测试类中删除涉及AsNoTrackingSetup会发生什么?

给你所有的MockBehavior.Strict可能会有所帮助。 在这种情况下,您将发现静态方法调用它们的成员是否可由Moq模拟(即一般意义上的虚方法/属性)。 也许你可以在必要时模拟非静态方法DbQuery.AsNoTracking