Telerik blogs
If you’ve never done Test Driven Development or aren’t even sure what this "crazy TDD stuff” is all about than this is the series for you. Over the next 30 days this series of posts take you from “I can spell TDD” to being able to consider yourself a “functional” TDD developer. Of course TDD is a very deep topic and truly mastering it will take quite a bit of time, but the rewards are well worth it. Along the way I’ll be showing you how tools like JustCode and JustMock can help you in your practice of TDD.
 
Previous Posts in this Series: Day 11 – What’s the Deal with “Mocking?”

“Mocking” is one of those magical concepts derived from OOP that makes TDD possible. But as you saw in the last post, there are many different kind of mocks and each has its own strengths, weaknesses and purposes. We’ll discuss most of these types of mocks at some point in this series. But in this post I’m going to demonstrate one of the most common type of mocks you’ll use; the Stub.

 

Sometimes to Move Forward, You Need to Take a Step Back…

In the previous post in this series I showed you a prototype of what the PlaceOrder for an OrderService in an e-commerce application may look like. To demonstrate mocking, we’ll be developing a production version of this business logic using TDD. That means we start with a business requirement:

Assuming a user has logged into the application and placed items in a shopping cart, the application should enable to user to place an order based on the items in the shopping cart. Users should be able to order any number of different items they wish. Users may not order a zero or lower quantity of any item. If the user attempts to order a quantity of zero or less for any item an exception should be thrown and the entire order aborted (the shopping cart should NOT be emptied). Once the order quantity validation rule has been validated the order should be saved to the database via the Orders Database service and linked to the customer who placed the order. Calls will be made to the billing and order fulfillment systems to launch their respective workflows. A log entry shall be made to show that the order was placed. If the order cannot be placed for any reason other than a failure of the validation rules, the error will be logged and an exception will be thrown. Upon a successful placement of an order the shopping cart will be emptied and the order id (from the Order Database service) will be returned.

This is quite a big business requirement. It will surly result in several test cases we can use to write unit tests, but let’s start with the easiest first:

When a user attempts to order an item with a quantity of greater than zero the order id should be returned.

This is a simple case and gives us a good place to start. As this is the first requirement and first test, I have no code or even a Visual Studio solution. To get started I’m going to create a blank Visual Studio solution for my project, which will call TddStore. Next I’ll create a class library for my unit tests called TddStore.UnitTests and I’ll use NuGet to add a reference to NUnit to my unit test library. If you need a refresher on how to do any of these tasks you can check out the post for Day Two. After completing these steps my Solution Explorer should look something like Figure 1:

 image

Figure 1 – My solution and unit test project are created and NUnit has been referenced

Using the JustCode rename command (also shown in the Day Two post) I rename Class1 to OrderServiceTests. I use the NUnit TestFixture and Test attributes to write my first test (I’ve used JustCode to get rid of my unused using statements):

 1: using System;
 2: using System.Linq;
 3: using NUnit.Framework;
 4:  
 5: namespace TddStore.UnitTests
 6: {
 7:     [TestFixture]
 8:  class OrderServiceTests
 9:     {
 10:         [Test]
 11:  public void WhenUserPlacesACorrectOrderThenAnOrderNumberShouldBeReturned()
 12:         {
 13:  
 14:         }
 15:     }
 16: }

(get code sample)

For this example we will assume that another team has been working this application as well and has provided me with the implementation of ShoppingCart and Order as well as interfaces for the OrderDataService, BillingService, FulfillmentService and Logging Service in a class library project. This TddStore.Core project is also where I’m expected to place my OrderService and any ancillary classes I create to support it. If you are following along with this example you should create a C# class library project in your solution called TddStore.Core and add these files. You should then add a reference to this new Core project from your unit test project.

For this test I need to create an order by calling a yet to be defined method on a yet to be created class. Per the TDD workflow, I write my test first:

 1:         [Test]
 2:  public void WhenUserPlacesACorrectOrderThenAnOrderNumberShouldBeReturned()
 3:         {
 4:  //Arrange
 5:             var shoppingCart = new ShoppingCart();
 6:             shoppingCart.Items.Add(new ShoppingCartItem { ItemId = Guid.NewGuid(), Quantity = 1 });
 7:             var customerId = Guid.NewGuid();
 8:             var expectedOrderId = Guid.NewGuid();
 9:             var orderService = new OrderService();
 10:  
 11:  //Act
 12:             var result = orderService.PlaceOrder(customerId, shoppingCart);
 13:  
 14:  //Assert
 15:             Assert.AreEqual(expectedOrderId, result);
 16:         }

(get sample code)

The code in this test should be pretty easy to understand by now; in my “Arrange” section I’m creating an instance of my shopping cart and adding an item to it. I’m also creating dummy order and customer id’s to use for my test. Finally I’m instantiating an instance of the OrderService to test against. My “Act” and “Assert” sections are also pretty self-explanatory; I’m calling PlaceOrder with the customer Id and shopping cart I create in the Arrange and in the Assert I’m verifying that the order id I get back as my result is what I was expecting.

At this point I run the test to watch it fail and then start writing the simplest thing that will make the test pass. Eventually, I come up with this:

 1:  public class OrderService
 2:     {
 3:  public object PlaceOrder(Guid customerId, ShoppingCart shoppingCart)
 4:         {
 5:  // TODO: Implement this method
 6:  throw new NotImplementedException();
 7:         }
 8:     }

Based on my test case, I need a reference to the OrderDataService class. I refactor my OrderService class to accommodate injection of this via the constructor:

 1:  public class OrderService
 2:     {
 3:  private IOrderDataService _orderDataService;
 4:  
 5:  public OrderService(IOrderDataService orderDataService)
 6:         {
 7:             _orderDataService = orderDataService;
 8:         }
 9:  
 10:  public object PlaceOrder(Guid customerId, ShoppingCart shoppingCart)
 11:         {
 12:  // TODO: Implement this method
 13:  throw new NotImplementedException();
 14:         }
 15:     }

(get sample code)

I’ve given my PlaceOrder method access to an instance of the OrderDataService (via the IOrderDataService interface), but now my test no longer compiles. The reason is that the default constructor for OrderService no longer exists; I need to pass something that implements the IOrderDataService interface to my OrderService.

The Next Step

As I mentioned in my previous post I’ll be using Telerik’s JustMock mocking framework for this series. In this post I’ll be using the JustMock Lite framework. Since I’m using JustMock Lite I can use NuGet to add JustMock to my TddStore.UnitTests library. Note: If you are using the NuGet console the name of the JustMock Lite package is JustMock.

Now that I have access to JustMock in my TddStore.UnitTests project I can create a stub for the IOrderDataService.

 1: using System;
 2: using System.Linq;
 3: using NUnit.Framework;
 4: using TddStore.Core;
 5: using Telerik.JustMock;
 6:  
 7: namespace TddStore.UnitTests
 8: {
 9:     [TestFixture]
 10:  class OrderServiceTests
 11:     {
 12:         [Test]
 13:  public void WhenUserPlacesACorrectOrderThenAnOrderNumberShouldBeReturned()
 14:         {
 15:  //Arrange
 16:             var shoppingCart = new ShoppingCart();
 17:             shoppingCart.Items.Add(new ShoppingCartItem { ItemId = Guid.NewGuid(), Quantity = 1 });
 18:             var customerId = Guid.NewGuid();
 19:             var expectedOrderId = Guid.NewGuid();
 20:  
 21:             var orderDataService = Mock.Create<IOrderDataService>();
 22:             OrderService orderService = new OrderService(orderDataService);
 23:  
 24:  //Act
 25:             var result = orderService.PlaceOrder(customerId, shoppingCart);
 26:  
 27:  //Assert
 28:             Assert.AreEqual(expectedOrderId, result);
 29:         }
 30:     }
 31: }

The first step is to create the mock object. Before I can do that I need to add a “using” statement to the beginning of the OrderService file for the Telerik.JustMock namespace (line 5). On line 21 I create a mocked instance of the IOrderDataService interface. As this object implements the IOrderDataService interface I can pass it in as a constructor argument for OrderService, as seen on line 22. Next I need to add some logic to my business domain method (PlaceOrder on the OrderService) to use the IOrderDataService instance:

 1:  public object PlaceOrder(Guid customerId, ShoppingCart shoppingCart)
 2:         {
 3:             var order = new Order();
 4:  return _orderDataService.Save(order);
 5:         }

(get sample code)

This code bears some explanation. According to our test case we simply need to pass the method under test a shopping cart with at least one item in it and get back an order id. There’s nothing specific in this test case about what to do if a validation rule fails or how to build an order object from the items in our shopping cart. The current unit test does meet our current test case, and therefore verifies that the code will perform as described by the test case.

Dont panic We are still (and always) in the phase where we are trying to write the simplest code to make the test pass. At this point you probably have a couple questions. How are we actually sure the validation rules are present and working? How are we sure that the instance of Order that we are creating is being built correctly? The answer to both of these questions is that as we continue to fulfill the requirement we will create more test cases, including test cases to cover those two questions. Once we have test cases we can write unit tests. Once we have unit tests we can write code. For the purposes of this post we’ll continue with our current test cases, but we will address these two and other test cases from this requirement in future posts.

At this point I want to run my tests again. The test should be failing because while I’ve supplied all the needed dependencies that have enabled me to write the code that should make the test pass, I’m still not getting back the value for order id that I expected (Figure 2)

image

Figure 2 – Tests are failing

While we have created a mock object to stand in for our OrderDataService, we haven’t told it what to do when someone actually calls it. Referring to the list of types of mock in the previous post, what we currently have is a “Dummy". We need to elevate it to an actual Stub.

 1:         [Test]
 2:  public void WhenUserPlacesACorrectOrderThenAnOrderNumberShouldBeReturned()
 3:         {
 4:  //Arrange
 5:             var shoppingCart = new ShoppingCart();
 6:             shoppingCart.Items.Add(new ShoppingCartItem { ItemId = Guid.NewGuid(), Quantity = 1 });
 7:             var customerId = Guid.NewGuid();
 8:             var expectedOrderId = Guid.NewGuid();
 9:  
 10:             var orderDataService = Mock.Create<IOrderDataService>();
 11:             Mock.Arrange(() => orderDataService.Save(Arg.IsAny<Order>())).Returns(expectedOrderId);
 12:             OrderService orderService = new OrderService(orderDataService);
 13:  
 14:  //Act
 15:             var result = orderService.PlaceOrder(customerId, shoppingCart);
 16:  
 17:  //Assert
 18:             Assert.AreEqual(expectedOrderId, result);
 19:         }

On line 11 I am using the Mock.Arrange command to setup my orderDataService mock object, which essentially makes this orderDataService mock object into a stub. The Arrange method takes a Linq expression describing the method on the specific stub object I want to define a behavior for. In this case I’m telling my stub that I want it to respond to calls to the Save method. As part of this Linq expression I can define a parameter list for my stub. I can specify specific value if I want. For example, if Save took an integer as a parameter I could state that I want this particular arrangement on this stub to only respond when the Save method is called with an integer value of 42. If I called the mock with a value other than 42 it would return the default value of its particular return type (for example, it would return zero in the return type was an int, long or any numerical type). This is why when I ran the tests previously the orderDataService mock returned an empty (all zero’s) Guid. This is referred to as “loose mocking.” Will discuss loose and strict mocking in a future post.

In this case I’m passing in an instance of an Order object. I don’t really need to be worried about making sure I get a specific Object right now, so I’m using what’s known as a “Matcher.” A Matcher is essentially a way of telling an arrangement that I don’t want it to be too concerned with the specifics of a parameter, I just want to define a behavior for parameters that meet a certain pattern. In this case I’m telling JustMock that I just care that an Order object has been passed in as a parameter. I don’t care where it came from or what’s in it so long as it’s an instance of Order. Matchers are powerful tools in mocking and I’ll be explaining them in a future post.

One thing to keep in mind when writing arrangements for stubs or mocks is the fundamental difference between value types and reference types in .NET. When I create an arrangement with a value type the mock evaluates whether the parameter matches or not by looking at the values. One is always one and true is always true. This mirrors how value types are treated in .NET in general. When working with reference types the mock is not going to validate that the two objects are equal, it’s instead going to attempt to verify that they are the same object. For this reason, if I were to create an Order object in my test and use that as my expected parameter it would not be able to match the parameters as they are two different instances of Order. I’ll discuss how to handle this in future posts, but for now I just wanted to remind you of this aspect of testing and .NET development.

Finally I’m telling my mock that if a call is made to my mock or OrderDataService and it matches the criteria defined in my Arrange expression I want it to return a specific value, in this case the expectedOrderId. And that’s it; with one line of code I have elevated my Dummy mock object to a Stub. If I run my test now I can see that it passes and I have fulfilled my current test case (Figure 3)

image

Figure 3 – The test passes

Summary

We’ve covered quite a bit of ground in this post. We defined a requirement then derived a test case from that requirement. We used our test case to define a unit test and then wrote just enough code to make that test pass.In addition to all that work we wrote our first mock object; a stub that responded to a method call.

Stubs are the one of the easiest and perhaps the most common types of mocks you will create. But they are one tool in your mocking tool box; there are others you will need to understand to truly be a productive TDD developer. Mocking is a deep, and at times, complex topic. We will be spending the bulk of the remaining posts in this series discussing the different types of mocks as well as patterns for successful mocking as well as anti-patterns to avoid.

Continue the TDD journey:

JustCode download banner image

JustMock banner


About the Author

James Bender

is a Developer and has been involved in software development and architecture for almost 20 years. He has built everything from small, single-user applications to Enterprise-scale, multi-user systems. His specialties are .NET development and architecture, TDD, Web Development, cloud computing, and agile development methodologies. James is a Microsoft MVP and the author of two books; "Professional Test Driven Development with C#" which was released in May of 2011 and "Windows 8 Apps with HTML5 and JavaScript" which will be available soon. James has a blog at JamesCBender.com and his Twitter ID is @JamesBender. Google Profile

Comments

Comments are disabled in preview mode.