다음을 통해 공유


Unit testing with Microsoft Moles

I’ve been thinking for a while: “How come Microsoft doesn’t have a Mocking Library like Moq, Rhino Mock, NMock, Typemock, etc?”. Off course you could argue that we don’t need one of our own, you could use one of the existing once or you could just implement some stubs yourself. I’ve lately been drawn towards Moq for its great support for refactoring, but Rhino Mock is the framework I’ve used the most.

Last night, I discovered something fun though. It turns out that Microsoft Research have been busy with something called Microsoft Moles and a first release is now out for you to try out. Let me introduce Microsoft Moles to you by this example.

Let’s say you have this simplified WCF Order Service, implemented like this:

    1: using System;
    2: using System.ServiceModel;
    3:  
    4: namespace AI.ServiceLibrary
    5: {
    6:     // Service Contract
    7:     [ServiceContract(
    8:         Namespace = "https://assemblyinfo.com/Contracts/OrderService/2010/03", 
    9:         Name = "OrderService")]
   10:     public interface IOrderService
   11:     {
   12:         [OperationContract]
   13:         int AddOrder(Order order);
   14:     }
   15:  
   16:     // Data Contracts
   17:     public class Order
   18:     {
   19:         public int ID { get; set; }
   20:         public DateTime OrderDate { get; set; }
   21:         public string CustomerName { get; set; }
   22:         public OrderDetail[] Details { get; set; }
   23:     }
   24:  
   25:     public class OrderDetail
   26:     {
   27:         public string ArticleNumber { get; set; }
   28:         public int Quantity { get; set; }
   29:     }
   30:  
   31:     // Simplified OrderService Implementation
   32:     public class OrderService : IOrderService
   33:     {
   34:         public int AddOrder(Order order)
   35:         {
   36:             // Set OrderDate to current date
   37:             order.OrderDate = DateTime.Now;
   38:  
   39:             // Save order using Order Repository
   40:             var repository = new OrderRepository();
   41:             int orderId = repository.SaveOrder(order);
   42:  
   43:             // Return Order ID generated by database
   44:             return orderId;
   45:         }
   46:     }
   47: }

 

So lets create some Unit Tests for this WCF Service, but first, let us recapture what a Unit Test really is. A Unit Test is a test that tests the smallest testable part of your code. In a unit test we don’t want to be dependent of other parts of our system and specially not dependent of other products like the file system, a SQL Server or any other third party application. Don’t get me wrong here, you could and perhaps should write automatic tests that test the integration between several components and applications, but those tests are not Unit Tests, those are Integration Tests. In a unit test we want to isolate our test to test only one (or the smallest) part of our code.

If you look at the implementation of OrderService above, you can see that we have a strict dependency for a class called OrderRepository at row 40, that seems to save our order to a database and returns a new OrderId. This is a problem for us because we can not test our OrderService without testing our OrderRepository as well.

Another problem can be found at row 37 where we set the OrderDate to the current date and time. How can we predict that value? We don’t know at what time our test is going to be run.

    1: [TestMethod]
    2: public void CanAddOrderWithoutMole()
    3: {
    4:     var service = new OrderService();
    5:     var order = new Order()
    6:     {
    7:         CustomerName = "Test Customer",
    8:         Details = new OrderDetail[]
    9:         { 
   10:             new OrderDetail() {ArticleNumber="A123", Quantity=1 }, 
   11:             new OrderDetail() {ArticleNumber="B456", Quantity=2 }}
   12:     };
   13:  
   14:     var orderId = service.AddOrder(order);
   15:  
   16:     Assert.AreEqual( /* <What OrderID should I use here> */, orderId);
   17:  
   18:     // We can't control OrderDate because we don't know the exact time
   19:     // the test is executed. We could guess quite well, but if the call
   20:     // to AddOrder takes time, we can't be sure.
   21: }

The traditional way to fix this problem is to refactor the original code to implement some kind of pattern that helps us substitute our hard coded dependencies. One popular pattern is the Dependency Injection Pattern which essentially says that every class should take its dependent objects as in-parameters to its constructor (or through properties). I won’t go in to that pattern right now, but this is a good pattern and as I’ll try to cover in a follow up post, I’ll show you how Microsoft Mole might help you even though you have decided to use this pattern.

But if we don’t want to or are unable to refactor our code, how do we do then? This is when Microsoft Moles comes as a savior. With Microsoft Mole, you can substitute almost any .NET method with a version of your own. Yeah, that’s right. If you don’t like the current implementation of DateTime.Now, you could substitute it to always return a date that you control or if you don’t have full control of what the AddOrder method on the OrderRepository does, then substitute it for another implementation. Let me show you.

    1: [TestMethod]
    2: [HostType("Moles")]
    3: public void CanAddOrderWithoutMole()
    4: {
    5:     int callesToSaveOrder = 0;
    6:  
    7:     // Replace the current implementation of DateTime.Now
    8:     // with one that allways return the same date
    9:     MDateTime.NowGet = () => new DateTime(2010, 03, 07, 14, 20, 0);
   10:  
   11:     MOrderRepository.AllInstances.SaveOrderOrder = (r, o) =>
   12:         {
   13:             // Increase counter to be sure of how many times
   14:             // our implementation of SaveOrder gets called
   15:             callesToSaveOrder++;
   16:             
   17:             // Customer name should be the one we provided
   18:             Assert.AreEqual("Test Customer", o.CustomerName);
   19:  
   20:             // Order date should be the 2010-03-07 14:20:00, because
   21:             // we just replaced the implementation of DateTime.Now
   22:             Assert.AreEqual(new DateTime(2010, 03, 07, 14, 20, 0), o.OrderDate);
   23:  
   24:             // Allways return 42 as OrderID
   25:             return 42; 
   26:         };
   27:     
   28:     var service = new OrderService();
   29:     var order = new Order()
   30:     {
   31:         CustomerName = "Test Customer",
   32:         Details = new OrderDetail[]
   33:         { 
   34:             new OrderDetail() {ArticleNumber="A123", Quantity=1 }, 
   35:             new OrderDetail() {ArticleNumber="B456", Quantity=2 }}
   36:     };
   37:  
   38:     var orderId = service.AddOrder(order);
   39:  
   40:     // Make sure the OrderID is 42 ...
   41:     Assert.AreEqual(42, orderId);
   42:     // ... and that we only made one call to SaveOrder
   43:     Assert.AreEqual(1, callesToSaveOrder);
   44: }

At line 9 above, you can see how I substitute the current implementation of DateTime.Now with an own implementation that always returns 2010-03-07 14:20:00. You can see that I use a “Magic Class” called MDateTime to do that. And on line 11 you can see how I replace the current implementation of SaveOrder of the OrderRepository class by interacting with another “Magic Class” called MOrderRepository. As it turns out, this is no magic at all.

Microsoft Moles generates classes for me according to my specifications in .moles files and in this example I’ve configured Moles to generate Mole Types for mscorlib.dll and my service library. You can configure exactly what classes gets generated to save some execution and generation times, but in this example I’ve just let Moles to generate Mole Types for the complete assemblies.

Content of: mscorlib.moles

    1: <?xml version="1.0" encoding="utf-8" ?>
    2: <Moles xmlns="https://schemas.microsoft.com/moles/2010/">
    3:   <Assembly Name="mscorlib" />
    4: </Moles>

Content of: AI.ServiceLigrary.moles

    1: <?xml version="1.0" encoding="utf-8" ?>
    2: <Moles xmlns="https://schemas.microsoft.com/moles/2010/">
    3:   <Assembly Name="AI.ServiceLibrary" />
    4: </Moles>

Moles also made me aware that I had to add the following attribute at assembly level, which I did in my AssemblyInfo.cs file:

    1: [assembly: MoledType(typeof(System.DateTime))]

So, that’s it, when I run my Unit Test, and yes this is really a Unit Test and not an Integration Test, it passes and informs me that my AddOrder method inside my OrderService works as it should. Just to prove that I’m not doing Integration Testing here I’ll even show you my implementation of my OrderRepository:

    1: public class OrderRepository
    2: {
    3:     public int SaveOrder(Order order)
    4:     {
    5:         throw new NotImplementedException();
    6:     }
    7: }

Amazing, isn’t it? We have just made a Unit Test out of code that normally isn’t Unit Testable at all. With that said, I still like to point out the following:

  • Microsoft Mole is a great! It can help you Unit Test what wasn’t unit testable before (actually some Mocking Frameworks like Typemock have made this possible before).
  • I still want my systems to be loosely coupled and would still recommend you to implement some patterns to make your system just that. Just because Moles might save you some troubles of implementing one of those patterns, doesn’t make it necessary a good thing.
  • Make sure you understand how to implement the Dependency Injection Pattern and know how to use Inversion of Control Containers like Unity, NSpring, etc. Microsoft Moles can also help you implement the stubs you would need to Unit Test you components that implements the Dependency Injection Pattern.
  • Microsoft PEX is a tool that will help you implement Unit Tests with high code coverage and is a very interesting technology. Make sure you’ll have a look at that as well. I might even cover that topic later as well.

Please look at this post on the Visual Studio Team Test blog to find out more information and how you can download Pex and Moles.

Comments

  • Anonymous
    March 24, 2010
    The comment has been removed

  • Anonymous
    August 12, 2010
    Hi, that is nice. True. Is there  any working solution sample with code that you have used as samples? Can we look at that?

  • Anonymous
    February 27, 2011
    Very nice article. Especially w.r.t user defined class. I've a wcf something similar and I've created .mole for it. But when I type MWorkflowRequest (WorkflowRequest is an data contract), It's not recognised. Am I missing something? Please help.

  • Anonymous
    June 10, 2011
    This all looks really cool... does anybody see this a pretty big security breach though. Perhaps I'm not understanding exactly what Moles can do, but it seems like you can replace the functionality of any method, say for example a CheckPassword method or some such. Am I totally off base here?

  • Anonymous
    September 13, 2011
    Mycket bra artikel Kristofer. Ska se till att följa din blog nu.

  • Anonymous
    December 08, 2011
    Hi. Very nice article ! Do you know if Moles is supported in Silverlight 4 with VS 2010 ? I tried to use Moles to isolate a DateTime object in a Silverlight project and I couldn't, Thanks and keep up the good work.

  • Anonymous
    April 06, 2012
    Excellent article. Good to see example code not using DateTime! Did you hear that Moles was being integrated into Visual Studio 11 as Microsoft Fakes. I found myself writing a very similar post based on it.  Check it out here: www.richonsoftware.com/.../Using-Stubs-and-Shim-to-Test-with-Microsoft-Fakes-in-Visual-Studio-11.aspx Thanks again for the great article.