WAQS and unit tests: Mock the database

7 reasons to use WAQS

WAQS documentation

 

Unit testing implies without DB.

Imagine that you wrote this two specification methods:

public static bool HasOrderInLast120Days(string customerId, INorthwindWAQSEntities context)
{
    return context.Orders.Any(o => o.CustomerId == customerId && (DateTime.Now - o.OrderDate).Days < 120);
}

public static Invoice MakeInvoice(this Order o, INorthwindWAQSEntities context)
{
    Invoice invoice = new Invoice { OrderId = o.Id, CustomerId = o.CustomerId, Total = GetTotal(o), Discount = GetDiscount(o) };
    if (o.Customer != null)
    {
        invoice.CustomerCompanyName = o.Customer.CompanyName;
        invoice.CustomerContactName = o.Customer.ContactName;
    }
    foreach (var od in o.OrderDetails)
         invoice.InvoiceDetails.Add(new InvoiceDetail { OrderDetailId = od.Id, Quantity = od.Quantity, UnitPrice = od.UnitPrice, Discount = od.Discount,
Amount = GetAmount(od) });
    context.Invoices.Add(invoice);
    context.SaveChanges();
    return invoice;
}


How to test them without the DB?



The first cool thing is the fact that, as you can see, specifications using data context use an interface on it which is a good practice for mocking.



In addition, WAQS generates mocks for you that you can use very easily:



[TestMethod]
public void HasOrderInLast120DaysTrue()
{
    var o = new Order { OrderDate = DateTime.Now.AddMonths(-1), CustomerId = "AAAAA" };
    var context = new NorthwindWAQSEntitiesMock();
    context.Orders.Add(o);
    Assert.IsTrue(NorthwindSpecifications.HasOrderInLast120Days("AAAAA", context)); } [TestMethod] public void MakeInvoiceTest() {
    Customer c = new Customer { Id = "AAAAA", CompanyName = "CM", ContactName = "CN" };
    var o = new Order { Id = 1, Customer = c };
    o.OrderDetails.Add(new OrderDetail { UnitPrice = 8, Quantity = 5 });
    o.OrderDetails.Add(new OrderDetail { UnitPrice = 5, Quantity = 8 });
    var context = new NorthwindWAQSEntitiesMock();
    Invoice i2 = null;
    context.SaveChanges = _ => i2 = context.Invoices.Local.Single();
    var i = NorthwindSpecifications.MakeInvoice(o, context, getTotal_Order_Double_Func: o2 => 80, getAmount_OrderDetail_Double_Func:  ol => 40);
    Assert.IsNotNull(i2);
    Assert.AreEqual(i2, i);
    Assert.AreEqual(1, i.OrderId);
    Assert.AreEqual("AAAAA", i.CustomerId);
    Assert.AreEqual("CM", i2.CustomerCompanyName);
    Assert.AreEqual("CN", i2.CustomerContactName);
    Assert.AreEqual(80, i.Total);
    Assert.AreEqual(2, i.InvoiceDetails.Count);
    var il = i.InvoiceDetails[0];
    Assert.AreEqual(40, il.Amount);
    Assert.AreEqual(5, il.Quantity);
    Assert.AreEqual(8, il.UnitPrice);
    il = i.InvoiceDetails[1];
    Assert.AreEqual(40, il.Amount);
    Assert.AreEqual(8, il.Quantity);
    Assert.AreEqual(5, il.UnitPrice); }


How does it work without DB?



As we explained in the previous post, the code we test using WAQS is not exactly the same than the one we wrote in specifications. So, the query in HasOrderInLast120DaysTrue is not the one with IQueryable but it is one with IEnumerable:



public static bool HasOrderInLast120Days(string customerId, INorthwindWAQSEntities context)
{
    return context.Orders.Local.IncludeCustomer().Any(o => o.CustomerId == customerId && (DateTime.Now - o.OrderDate).Days < 120);
}


In MakeInvoiceTest method, we use a Mock context generated by WAQS which allows us to define a delegate in order to replace SaveChanges method.

This entry was posted in 16868, 18099. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>