简体   繁体   中英

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

In my MVC4 application almost every method does something with a database. 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.

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

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.

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. By using DI you can mock the projectContext class and make it return whatever you need. Check out Autofac ( http://www.codeproject.com/Articles/25380/Dependency-Injection-with-Autofac ), it might already be installed in you mvc solution.

Your problem is that your ShoppingCart class is directly coupled with the database layer.

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.

Depend on abstractions...

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