WAQS and unit tests

7 reasons to use WAQS

WAQS documentation

 

After writing your specifications code, it’s a good idea to test it.

For this, WAQS can also help.

 

WAQS.Server.Mock

First, we create a unit test project and we reference the server project.

As we previously did for Server and Client, we use a NuGet package for server unit tests. Its name is WCFAsyncQueryableServices.Server.Mock.

In NuGet Package Manager Console, we select the unit test project as default one.

Then, we use a new powershell command

WCFAsyncQueryableServicesServerMock ‘"C:\VS Projects\WAQSDemo\WAQSDemo.Web\Northwind.edmx"’ All

// Note that we have intellisense for it.

 

WAQS and unit tests

Imagine the following specifications methods:

[Virtual]
public static double GetDiscount(this Customer c)

    return 0;

 
[Override]
public static double GetDiscount(this VIPCustomer c)

    return 0.1;
}  
 
public static double GetAmount(this OrderDetail od)

    return (double)od.UnitPrice * od.Quantity * (1 – od.Discount);

 
public static double GetDiscount(this Order o)

    return GetDiscount(o.Customer);
}  
 
public static double GetTotal(this Order o)

    return o.OrderDetails.Sum(od => GetAmount(od)) * (1 – GetDiscount(o));
}  

 

Now imagine that we want to test methods the three last methods.

For the first one, we can use this basic code:

[TestMethod]
public void GetAmountTest()
{
    var od = new OrderDetail { Quantity = 10, UnitPrice = 2, Discount = 0 };
    Assert.AreEqual(20, od.GetAmount());
}


 



Tests and WAQS polymorphism



For the second one, we can use the following code.



[TestMethod]
public void OrderGetOrderDiscountTest()
{
    var o = new Order { Customer = new Customer() };
    Assert.AreEqual(0, o.GetDiscount());
    o = new Order { Customer = new VIPCustomer() };
    Assert.AreEqual(0.1, o.GetDiscount());
}



 



How does it work?



Based on specifications, WAQS generated methods GetDiscount with virtual / override keywords in entities as I explained here.



Because classes methods are used instead of extension methods in ambiguous cases it works fine.



In case you call the method like a static method instead of using extension syntax, WAQS duplicates the specification code you wrote in unit test project and change it a little bit like this:



public static double GetDiscount(this Customer c)
{
    VIPCustomer cAsVIPCustomer = c as VIPCustomer;
    if (cAsVIPCustomer != null)
    {
        return 0.1;
    }
    return 0;
}






 







Avoiding double tests



Now we want to test GetTotal method.



GetTotal method calls GetAmount and GetDiscount ones.



Unit test best practices recommend to not test GetAmount and GetDiscount in GetTotal test in this case.



So how to do it?



We can add a lot of abstraction to use stubs but it will be a pain to implement it so in this case, I do not recommend this way.



In 2012, Microsoft introduced shims with Microsoft fakes.



We can use this way but WAQS also proposes another one if you want to only mock other specifications methods.



As I explained, WAQS generates specification code in unit test project.



When it does, it determines other specifications methods dependences using Roslyn and proposes to use optional delegates to mock their calls.



So, in our sample, GetTotal unit test method becomes this one:



public static double GetTotal(this Order o,
   
Func<WAQSDemo.Web.OrderDetail, double> getAmount_OrderDetail_Double_Func = null
    Func<WAQSDemo.Web.Order, double> getDiscount_Order_Double_Func = null)

    return o.OrderDetails.Sum(od => 
        (getAmount_OrderDetail_Double_Func ==
null
           
NorthwindSpecifications.GetAmount(od) : 
            getAmount_OrderDetail_Double_Func(od)))
        * (1 - 
            (getDiscount_Order_Double_Func ==
null
               
NorthwindSpecifications.GetDiscount(o) : 
                getDiscount_Order_Double_Func(o)));
}









So, using this way, we can mock calls very easily:



[TestMethod]
public void GetTotalWithMocksTestMethod()
{
    var o = new Order();
    o.OrderDetails.Add(new OrderDetail());
    o.OrderDetails.Add(new OrderDetail());
    Assert.AreEqual(18, NorthwindSpecifications.GetTotal(o, getAmount_OrderDetail_Double_Func: ol => 10, getDiscount_Order_Double_Func: c => 0.1));
}


 



What do you think about it? Is it cool? Does it makes sense? What is your opinion?

This entry was posted in 16402, 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>