简体   繁体   English

如何使用Moq测试与数据库交互的方法?

[英]How can I test methods that interact with a database with Moq?

In my MVC4 application almost every method does something with a database. 在我的MVC4应用程序中,几乎每个方法都使用数据库。 Now I want to test these methods and I looked at this tutorial to do so. 现在我想测试这些方法,我看了这个教程。 It is recommended there to use Moq to make mock objects. 建议在那里使用Moq来制作模拟对象。

In this particular case I want to test my GetTotal method of the ShoppingCart class (based on Microsoft Tutorial ) which depends on the AddToCart method which look like this 在这种特殊情况下,我想测试ShoppingCart类的GetTotal方法(基于Microsoft教程 ),该方法依赖于AddToCart方法,该方法看起来像这样

public class ShoppingCart() {
    projectContext db = new projectContext ();

    public virtual void AddToCart(Product product)
    {
        var cartItem = db.Carts.SingleOrDefault(
            c => c.CartId == ShoppingCartId
            && c.ProductId == product.ProductId);

        if (cartItem == null)
        {  
            cartItem = new Cart
            {
                ProductId = product.ProductId,
                CartId = ShoppingCartId,
                Count = 1,
                DateCreated = DateTime.Now
            };
            db.Carts.Add(cartItem);
        }
        else
        {
            cartItem.Count++;
        }
        db.SaveChanges();
    }

    public virtual decimal GetTotal()
    {  
        decimal? total = (from cartItems in db.Carts
                          where cartItems.CartId == ShoppingCartId
                          select (int?)cartItems.Count *
                          cartItems.Product.Price).Sum();

        return total ?? decimal.Zero;
    }
}

As can be seen both methods depend on the projectContext instance db. 可以看出,两种方法都依赖于projectContext实例db。

When testing these methods I wanted to use mock objects like this: 在测试这些方法时,我想使用这样的模拟对象:

[TestClass]
public class ShoppingCartTest : DbContext
{

    [TestMethod]
    public void GetTotalTest()
    {
        // Arrange
        var _cart = new Mock<ShoppingCart>() { CallBase = true };
        var _mock = new Mock<Product>() { CallBase = true };
        _mock.SetupGet(m => m.Price).Returns(10.00M);

        // Act
        _cart.AddToCart() // cannot find method since no definiton can be found

        // Assert
       Assert.AreEqual(10.00M, _cart.GetTotal());// cannot find GetTotal method since no definiton can be found
    }

}

How can I possibibly test these methods? 我怎样才能可能测试这些方法? Is it possible to just create a "fake" database and use that? 是否可以创建一个“假的”数据库并使用它? Or can I adjust the mock objects in a way that methods can be used on them (using "mock methods" seems to me like missing the point of testing the actual methods...)? 或者我可以调整模拟对象的方式可以使用方法(使用“模拟方法”似乎我错过了测试实际方法的点......)?

Testing this is hard, and I'm not sure it's possible to mock this. 测试这很难,我不确定是否可以嘲笑它。 If you can use DI (Dependency Injection) you solve all your problems. 如果您可以使用DI(依赖注入),您可以解决所有问题。 By using DI you can mock the projectContext class and make it return whatever you need. 通过使用DI,您可以模拟projectContext类并使其返回您需要的任何内容。 Check out Autofac ( http://www.codeproject.com/Articles/25380/Dependency-Injection-with-Autofac ), it might already be installed in you mvc solution. 查看Autofac( http://www.codeproject.com/Articles/25380/Dependency-Injection-with-Autofac ),它可能已经安装在您的mvc解决方案中。

Your problem is that your ShoppingCart class is directly coupled with the database layer. 您的问题是您的ShoppingCart类直接与数据库层耦合。

Hide your dependency on the concrete projectContext behind an abstraction, for example an interface, so you can replace it when testing the production code that use it. 隐藏对抽象背后的具体projectContext依赖,例如接口,因此您可以在测试使用它的生产代码时替换它。

Depend on abstractions... 取决于抽象......

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

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