繁体   English   中英

模拟AsNoTracking实体框架

[英]Mock AsNoTracking Entity Framework

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

public interface IUnitOfWork
{
    IDbSet<TEntity> Set<TEntity>() where TEntity : class;
    int SaveAllChanges();
}

public class Entites : DbContext, IUnitOfWork
{
    public virtual DbSet<Product> Products { get; set; }  // This is virtual because Moq needs to override the behaviour

    public new virtual IDbSet<TEntity> Set<TEntity>() where TEntity : class   // This is virtual because Moq needs to override the behaviour 
    {
        return base.Set<TEntity>();
    }

    public int SaveAllChanges()
    {
        return base.SaveChanges();
    }
}

    public class ProductService
{
    private readonly IDbSet<Product> _products;
    private readonly IUnitOfWork _uow;

    public ProductService(IUnitOfWork uow)
    {
        _uow = uow;
        _products = _uow.Set<Product>();
    }
    public IEnumerable<Product> GetOrderedProducts()
    {
        return _products.AsNoTracking().OrderBy(x => x.Name).ToList();
    }
}

    [TestFixture]
public class ProductServiceTest
{
    private readonly ProductService _productService;

    public ProductServiceTest()
    {
        IQueryable<Product> data = GetRoadNetworks().AsQueryable();
        var mockSet = new Mock<DbSet<Product>>();
        mockSet.As<IQueryable<Product>>().Setup(m => m.Provider).Returns(data.Provider);
        mockSet.As<IQueryable<Product>>().Setup(m => m.Expression).Returns(data.Expression);
        mockSet.As<IQueryable<Product>>().Setup(m => m.ElementType).Returns(data.ElementType);
        mockSet.As<IQueryable<Product>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
        var context = new Mock<Entites>();
        context.Setup(c => c.Products).Returns(mockSet.Object);
        context.Setup(m => m.Set<Product>()).Returns(mockSet.Object);
        context.Setup(c => c.Products.AsNoTracking()).Returns(mockSet.Object);
        _productService = new ProductService(context.Object);
    }

    private IEnumerable<Product> GetRoadNetworks()
    {
        return new List<Product>
        {
            new Product
            {
                Id = 1,
                Name = "A"
            },
            new Product
            {
                Id = 2,
                Name = "B"
            },
            new Product
            {
                Id = 1,
                Name = "C"
            }
        };
    }

    [Test]
    public void GetOrderedProductTest()
    {
        IEnumerable<Product> products = _productService.GetOrderedProducts();
        List<string> names = products.Select(x => x.Name).ToList();
        var expected = new List<string> {"A", "B", "C"};
        CollectionAssert.AreEqual(names, expected);
    }
}

问题是AsNoTracking在单元测试中返回null 在此处输入图片说明

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

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

由于source (您要模拟的DbSet<Product> )确实是DbQuery (因为DbSet是从DbQuery ),因此它试图调用“真实”(未经模拟)的AsNoTracking()方法,该方法正确地返回null。

尝试模拟AsNoTracking()方法:

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

你有:

context.Setup(c => c.Products).Returns(mockSet.Object);
context.Setup(m => m.Set<Product>()).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()有什么区别?

如果AsNoTracking测试类中删除涉及AsNoTrackingSetup ,会发生什么情况?

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

您可以使用实体框架工作量来模拟AsNoTracking(),也可以使用工作量来模拟Db事务和实体状态-工作量的官方网站

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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