30 Days of TDD – Day 16 – Using Specific Parameters in Stubs

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.

In a previous post we created a relatively simple stub to stand in for our OrderDataService. Our current stub is setup to return a canned result without worrying too much about what the value of our input parameter is. There are cases where a mock like this acceptable, but in most cases you’ll find that you want to have a specific response for a specific parameter. Luckily that’s not very difficult and today we will create a stub with that exact ability.

Moving Right Along…

We’ll be continuing with the example from our previous few posts. For review, our business requirement can be found in this post. As part of this feature we need to integrate with an external order fulfillment system. The next test cases I’ve decided to tackle are around interacting with the order fulfillment system. Instead of building our own order fulfillment infrastructure, management has decided to outsource this. This means that the order fulfillment system we will need to deal with is an external web service. It also means that we will need to provide with some customer information, notably name and address.

This means that we now need to interact with another external resource, the CustomerService to retrieve information about our customer. To help use with this we’ve been supplied with an Address and a Customer class:

Both entities and the interface for the Customer Service were added to the TddStore.Core project.

At this point I should start thinking about the first test case for interacting with my OrderFulfillment Service, which oddly enough has nothing to do with the OrderFulfillment Service. In this case I want to start by making sure that my OrderService is properly using my CustomerService. I’ll tackle the “happy path” first:

When a valid customer places an order (that passes validation) then order should be placed and an order number should be returned.

Yes, this looks similar to the beginnings of the WhenUserPlacesACorrectOrderThenAnOrderNumberShouldBeReturned test. No, I shouldn’t just change the WhenUserPlacesACorrectOrderThenAnOrderNumberShouldBeReturned test to also test the CustomService interaction. The purpose of the original test is to insure that the basic interaction with the OrderDataSevice works. The details of those interactions may change independently of how the method interacts with the CustomerService. As these tests evolve the need to create more involved mocks for the OrderDataService will be confined to tests that verify the interaction with the OrderDataService and vice versa. This enables both interactions (from OrderService to OrderDataService and from OrderService to CustomerService) to change (mostly) independently of each other, which leads to less brittle tests. It also helps me when a test fails as I’ll know more precisely if it was the interaction with the OrderDataService or the CustomerService that broke it, helping me know where to look first.

Before I go any further, I need to declare an instance variable for my CustomerService mock in the OrderServiceTests class. I also need to instantiate it in the SetupTestFixture method:

I know that for my new requirements based around my OrderFultillment service I will need to retrieve a customer from the CustomerService. I’ve already declared a mock for the CustomerService so right now I just need to arrange it. In this case I want my stub to return a specific instance of Customer when the GetCustomer method is called with a specific parameter. In the code I took from the other test I’ve already declared a customer id. The next step is to create an instance of Customer for my stub to return:

In my creation of the customerToReturn object I populated the Customer object with the Id (in this case the same customer Id I declared on line 7) and a first and last name. I don’t technically need first or last name right now, but I like to populate as many fields on an object as I can in testing. The reason is that while there’s nothing in my code that uses or even cares about those fields right now that could change. The logic this test is designed to check could be changed down the road by another test that makes the values in these fields meaningful. If I didn’t populate those values here there’s a change this test could fail. Or potentially, not fail when it should!

Now that I have my input and output values defined I can arrange my stub. In this case I only want my CustomerService stub to return the cutsomterToReturn when the GetCustomer method is called with the customerId value. I also expect that this method will be called exactly once:

At this point I can’t run my tests because my code will not compile. I don’t have a reference to the CustomerService in my OrderService. So, the next step is to change the OrderService class to accept the ICustomerService interface as a dependency which I’ll inject via the constructor (I’ve removed the PlaceOrder method from this listing to make this listing a little clearer):

Running my tests again shows me that my code still doesn’t compile. The reason is that in SetupTestFixture method of our OrderServiceTests we are trying to create an instance of OrderService without providing an instance ICustomerService to the constructor. I need change this method to provide a mock to the OrderService constructor (I’ve removed the using statements and test methods from this listing in the interest of clarity):

Now my test is ready to run! And as you can see in Figure 2, it passes:

Figure 2 – The test passes.

One thing you might be asking is why I didn’t capture the result of the PlaceOrder method like I did in the original test. The reason is that for this test I didn’t care what the order number was; I was only testing the interaction with the CustomerService. In fact, but not needing an order number I also didn’t need to arrange a mock for the OrderDataService, test the result value against an expected result or assert the the mock for the OrderDataService was invoked properly. I was able to write a test that was focused on one thing; the interaction with the CustomerService and was able to insulate myself from potential changes in the OrderDataService. Will there come a day when the requirements dictate that this test arrange a mock of the OrderDataService? Perhaps, but until that day comes we aren’t going to worry about it.

Summary

We accomplished a lot in this post; we started tackling one of the more complicated test cases for this feature, integrated with an external resource and wrote a slightly more intelligent stub capable of responding to specific parameters. As mentioned, finishing this test case will take a few more steps, but we are well on our way to being able to complete one more step in developing this application.

Progress, Telerik, and certain product names used herein are trademarks or registered trademarks of Progress Software Corporation and/or one of its subsidiaries or affiliates in the U.S. and/or other countries. See Trademarks or appropriate markings.