Skip to main content

C# mock and test helpers with example usage.

//
// TestHelpers.cs
//

using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using Moq;

namespace SharedKernel.Data
{
    public static class TestHelpers
    {
        public static DbSet<T> MockDbSet<T>() where T : class
        {
            return MockDbSet<T>(null);
        }

        public static DbSet<T> MockDbSet<T>(List<T> inMemoryData) where T : class
        {
            if (inMemoryData == null)
            {
                inMemoryData = new List<T>();
            }

            var mockDbSet = new Mock<DbSet<T>>();
            var queryableData = inMemoryData.AsQueryable();

            mockDbSet.Setup(m => m.Add(It.IsAny<T>())).Callback<T>(inMemoryData.Add);
            //mockDbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryableData.Provider);
            mockDbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryableData.Expression);
            mockDbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryableData.ElementType);
            mockDbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryableData.GetEnumerator());
            mockDbSet.Setup(x => x.AsNoTracking()).Returns(mockDbSet.Object);
            mockDbSet.Setup(x => x.Include(It.IsAny<string>())).Returns(mockDbSet.Object);

            mockDbSet.As<IDbAsyncEnumerable<T>>().Setup(m => m.GetAsyncEnumerator()).Returns(new TestDbAsyncEnumerator<T>(queryableData.GetEnumerator()));
            mockDbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(new TestDbAsyncQueryProvider<T>(queryableData.Provider));

            return mockDbSet.Object;
        }
    }
}

//
// TestDbAsyncQueryProvider.cs
//

using System.Collections.Generic;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;

namespace SharedKernel.Data
{
    internal class TestDbAsyncQueryProvider<TEntity> : IDbAsyncQueryProvider
    {
        private readonly IQueryProvider _inner;

        internal TestDbAsyncQueryProvider(IQueryProvider inner)
        {
            _inner = inner;
        }

        public IQueryable CreateQuery(Expression expression)
        {
            return new TestDbAsyncEnumerable<TEntity>(expression);
        }

        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
        {
            return new TestDbAsyncEnumerable<TElement>(expression);
        }

        public object Execute(Expression expression)
        {
            return _inner.Execute(expression);
        }

        public TResult Execute<TResult>(Expression expression)
        {
            return _inner.Execute<TResult>(expression);
        }

        public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken)
        {
            return Task.FromResult(Execute(expression));
        }

        public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
        {
            return Task.FromResult(Execute<TResult>(expression));
        }
    }

    internal class TestDbAsyncEnumerable<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T>, IQueryable<T>
    {
        public TestDbAsyncEnumerable(IEnumerable<T> enumerable) : base(enumerable) { }

        public TestDbAsyncEnumerable(Expression expression) : base(expression) { }

        public IDbAsyncEnumerator<T> GetAsyncEnumerator()
        {
            return new TestDbAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
        }

        IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
        {
            return GetAsyncEnumerator();
        }

        IQueryProvider IQueryable.Provider
        {
            get
            {
                return new TestDbAsyncQueryProvider<T>(this);
            }
        }
    }

    internal class TestDbAsyncEnumerator<T> : IDbAsyncEnumerator<T>
    {
        private readonly IEnumerator<T> _inner;

        public TestDbAsyncEnumerator(IEnumerator<T> inner)
        {
            _inner = inner;
        }

        public void Dispose()
        {
            _inner.Dispose();
        }

        public Task<bool> MoveNextAsync(CancellationToken cancellationToken)
        {
            return Task.FromResult(_inner.MoveNext());
        }

        public T Current
        {
            get
            {
                return _inner.Current;
            }
        }

        object IDbAsyncEnumerator.Current
        {
            get
            {
                return Current;
            }
        }
    }
}

//
// Example Usage
// ============================================================================

//
// WebSiteOrderingService.cs
//

using System.Collections.Generic;
using MvcSalesApp.Data;
using MvcSalesApp.Domain;
using MvcSalesApp.SharedKernel;
using MvcSalesApp.Web.CustomerFacing.ViewModels;

namespace MvcSalesApp.Services
{
    public class WebSiteOrderingService
    {
        private readonly WebSiteOrderData _siteOrderData;

        public WebSiteOrderingService(WebSiteOrderData siteOrderData)
        {
            _siteOrderData = siteOrderData;
        }

        public List<ProductLineItemViewModel> GetProductList()
        {
            var products = _siteOrderData.GetProductsWithCategoryForShopping();
            var lineitems = new List<ProductLineItemViewModel>();
            products.ForEach(p => lineitems.Add(new ProductLineItemViewModel
            {
                ProductId = p.ProductId,
                CategoryName = p.Category.Name,
                Description = p.Description,
                Name = p.Name,
                Quantity = 0,
                MaxQuantity = p.MaxQuantity,
                CurrentUnitPrice = p.CurrentPrice
            }));
            return lineitems;

        }

        public RevisitedCart ItemSelected(int productId, int quantity,
                                          decimal displayedPrice, string sourceUrl,
                                          string memberCookie, int cartId)
        {
            if (cartId == 0)
            {
                return InitializeCart(productId, quantity, displayedPrice, sourceUrl, memberCookie);
            }
            return AddItemToCart(productId, quantity, displayedPrice, cartId);

        }

        private RevisitedCart InitializeCart(int productId, int quantity,
                                             decimal displayedPrice, string sourceUrl,
                                             string memberCookie)
        {
            var cart = NewCart.CreateCartFromProductSelection
                       (sourceUrl, memberCookie, productId, quantity, displayedPrice);
            return _siteOrderData.StoreCartWithInitialProduct(cart);
        }

        private RevisitedCart AddItemToCart(int productId, int quantity,
                                            decimal displayedPrice, int cartId)
        {
            var cart = _siteOrderData.RetrieveCart(cartId);
            var item = cart.InsertNewCartItem(productId, quantity, displayedPrice);
            _siteOrderData.StoreNewCartItem(item);
            return cart;
        }

        public RevisitedCart RetrieveCart(string cartCookie)
        {
            if (CookieUtilities.IsCartCookie(cartCookie))
            {
                return _siteOrderData.RetrieveCart(cartCookie);

            }
            return null;
        }
    }

}

//
// WebSiteOrderingServiceTests.cs
//

using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using ShoppingCart.Data;
using ShoppingCart.Domain;
using SharedKernel.Data;

namespace ShoppingCart.Services.Tests
{
    [TestClass]
    public class WebSiteOrderingServiceTests
    {
        private string theUri = "http://www.thedatafarm.com";

        [TestMethod]
        public void InitializeCartReturnsRevisitedCart()
        {
            var scContext = new ShoppingCartContext {Carts = TestHelpers.MockDbSet<NewCart>()};
            var service = new WebSiteOrderingService(new WebSiteOrderData(scContext, new ReferenceContext()));
            Assert.IsInstanceOfType(service.ItemSelected(1, 1, 9.99m, theUri, null, 0), typeof (RevisitedCart));
        }

        [TestMethod]
        public void InitializeCartWithUnknownCustomerStoresZeroInCustomerId()
        {
            var newCartsInMemory = new List<NewCart>();
            var scContext = new ShoppingCartContext {Carts = TestHelpers.MockDbSet(newCartsInMemory)};
            var service = new WebSiteOrderingService(new WebSiteOrderData(scContext, new ReferenceContext()));
            service.ItemSelected(1, 1, 9.99m, theUri, null, 0);
            Assert.AreEqual(0, newCartsInMemory.FirstOrDefault().CustomerId);
        }

        [TestMethod]
        public void InitializeCartWithKnownCustomerStoresValueInCustomerId()
        {
            var newCartsInMemory = new List<NewCart>();
            var mockCustomer = new Mock<Customer>();
            mockCustomer.SetupGet(c => c.CustomerCookie).Returns("CustomerCookieABCDE");
            mockCustomer.SetupGet(c => c.CustomerId).Returns(1);
            var customersInMemory = new List<Customer> {mockCustomer.Object};
            var scContext = new ShoppingCartContext {Carts = TestHelpers.MockDbSet(newCartsInMemory)};
            var refcontext = new ReferenceContext {Customers = TestHelpers.MockDbSet(customersInMemory)};
            var service = new WebSiteOrderingService(new WebSiteOrderData(scContext, refcontext));
            service.ItemSelected(1, 1, 9.99m, theUri, "CustomerCookieABCDE", 0);
            Assert.AreNotEqual(0, newCartsInMemory.FirstOrDefault().CustomerId);
        }
    }
}