单元测试通用存储库“查找”方法 - MSTest,Moq,EF6

时间:2014-10-09 19:20:24

标签: c# asp.net-mvc-4 unit-testing moq entity-framework-6

我对Unit Testing和Moq很新,但我正在尝试使用Moq和MSTest为通用存储库设置单元测试。我确定有很多事情我可能做错了,但我真的可以使用帮助来测试我的通用存储库的基于表达式的参数。具体来说,我似乎无法让我的模拟存储库返回一个预期的对象列表这里是代码:


上下文

public class OrderContext : DbContext, IDisposable
{
    public virtual DbSet<Order> Orders { get; set; }

    public virtual void Commit()
    {
        base.SaveChanges();
    }

}


存储库接口/存储库

public interface IRepository<T> where T : class
{
    IEnumerable<T> GetManyBySearch(Func<T, bool> where);
}

public class RepositoryBase<T> : IRepository<T> where T : class
{
    private OrderContext _db;
    private DbSet<T> _dbSet;

    public RepositoryBase(OrderContext db) 
    {
        _db = db;
        _dbSet = _db.Set<T>();
    }

    // Get many records by search
    public virtual IEnumerable<T> GetManyBySearch(Func<T, bool> where)
    {
        return _dbSet.Where(where).AsQueryable();
    }
}


...在我的单元测试中,理想情况下我可以设置类似于this one的测试,只是我希望我的存储库返回基于内存对象数据的子集。表达式被传递给GetManyBySearch()方法。 目前,我的模拟存储库正在返回整个数据集,无论传递的表达式是什么。这是一个例子:


单元测试

    [TestMethod]
    [TestCategory("Repository Tests")]
    public void Order_Get_Many_By_Search()
    {

        Mock<OrderContext> mockDb = new Mock<OrderContext>();
        Mock<RepositoryBase<Order>> mockRepo = new Mock<RepositoryBase<Order>>(mockDb.Object);


        var data = new List<Order>()
        {
            new Order { OrderId = 1, OrderNumber = 111, OrderDate = DateTime.Now },
            new Order { OrderId = 2, OrderNumber = 222, OrderDate = DateTime.Now },
            new Order { OrderId = 3, OrderNumber = 222, OrderDate = DateTime.Now }
        }.AsQueryable();

        var expectedResults = data.Where(m => m.OrderNumber == 222);

        var mockSet = new Mock<DbSet<Order>>();
        mockSet.As<IQueryable<Order>>().Setup(m => m.Provider).Returns(data.Provider);
        mockSet.As<IQueryable<Order>>().Setup(m => m.Expression).Returns(data.Expression);
        mockSet.As<IQueryable<Order>>().Setup(m => m.ElementType).Returns(data.ElementType);
        mockSet.As<IQueryable<Order>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

        mockDb.Setup(m => m.Set<Order>()).Returns(mockSet.Object);

        mockRepo.Setup(m => m.GetManyBySearch(It.IsAny<Func<Order, bool>>()))
            .Returns(mockSet.Object.AsQueryable());

        List<Order> results = mockRepo.Object.GetManyBySearch(m => m.OrderNumber == 222).ToList(); // This returns the entire "data" dataset

        mockRepo.Verify(m => m.GetManyBySearch(It.IsAny<Func<Order, bool>>()), Times.Once());

        Assert.AreEqual(2, results.Count()); // This fails :(
    }


非常感谢任何帮助。提前谢谢。

1 个答案:

答案 0 :(得分:3)

我怀疑测试是否在指示的行上失败,因为您的示例数据有3个元素并且您断言它包含2:

var data = new List<Order>()
    {
        new Order { OrderId = 1, OrderNumber = 111, OrderDate = DateTime.Now },
        new Order { OrderId = 2, OrderNumber = 222, OrderDate = DateTime.Now },
        new Order { OrderId = 3, OrderNumber = 222, OrderDate = DateTime.Now }
    }.AsQueryable();

// <snip>...

Assert.AreEqual(2, results.Count()); 

但是,更大的问题是,在您的示例中,您实际上是在嘲笑您要测试的方法:

Mock<RepositoryBase<Order>> mockRepo = new Mock<RepositoryBase<Order>>(mockDb.Object);

// <snip>...

List<Order> results = mockRepo.Object.GetManyBySearch(m => m.OrderNumber == 222).ToList();

因此,您不会测试任何生产代码。相反,您只是测试模拟对象将执行您告诉他们的操作。

将模拟的存储库替换为实际实例,并将所有其他模拟对象注入其中。这将是一个很好的测试,GetManyBySearch方法返回您期望的结果。