How To Test Your Production Code: Test Spy

By using Dummy Objects and Test Stubs, we are able to control the inputs of the System Under Test to exercise every part of it during our tests. But of course, not every method that we want to test is going to have one just output or is going to change only the internals of the class that is under test. Most methods have side effects and are going to call other libraries or methods of other objects and we want to be sure that those method calls happen the right amount of times and with the correct parameters.

Let’s suppose we have a method that prepares an invoice when someone check’s out at a hotel. That method is part of a Registration class that takes in a Room and a Guest object and the BookingInformation with all the information about the booking period, like check-in and check-out dates number of people etc.

public class Registration
{
private Room _room;
private Guest _guest;
private BookingInformation _booking;
private readonly IPrinter _printer;
public Registration
(Room room, Guest guest,
BookingInformation booking, IPrinter printer)
{
_booking = booking;
_guest = guest;
_room = room;
_printer = printer;
}
public void CheckOut()
{
Dictionary<string, string> invoiceInformation =
PrepareInvoiceData();
_printer.Print(invoiceInformation);
}
private Dictionary<string, string> PrepareInvoiceData()
{
////
}
}

 

Then, when the method checkout gets called, it prepares a dictionary of strings and passes it to a library that prints the invoice. This dictionary an indirect output of our method and we want to check if it’s properly set, while also avoiding calling the real method that sends the file to the printer.

We notice that the a printer object is passed in the constructor of the class and that it implements the interface IPrinter. That means we could pass a special implementation of that interface and log the calls and the inputs passed to its methods.

public class PrinterSpy : IPrinter
{
public int PrintCallCount = 0;
public Dictionary<string, string> InvoiceParameters;
public void Print(Dictionary<string, string> parameters)
{
InvoiceParameters = parameters;
PrintCallCount++;
}
}

In particular we want to capture the dictionary that is passed to the print method and expose it as a public field to do the assertions. We could also check that we are calling the method just once, or that we are not calling it for when an error occurs.

[Test]
public void CheckPrintMethodIsCalledWithTheCorrectConfiguration()
{
// Arrange
var guest = new Guest
{
Name = "GuestName",
Surname = "GuestSurname",
Id = 1,
Phone = 111111111,
Address = "SomeAddress",
City = "SomeCity",
Country = "SomeCountry"
};
var room = new Room
{
Number = 1,
Type = RoomTypes.Suite,
Price = 1
};
var booking = new BookingInformation
{
CheckInDate = new DateTime(2016, 1, 1, 14, 0, 0),
CheckOutDate = new DateTime(2016, 1, 2, 10, 0, 0),
NumberPpl = 1,
};
// Act
var printer = new PrinterSpy();
var registration = new Registration(room, guest, booking, printer);
registration.CheckOut();
// Assert
var output = printer.InvoiceParameters;
Assert.AreEqual(1, printer.PrintCallCount);
Assert.AreEqual("GuestSurname GuestName",
output["GuestName"]);
Assert.AreEqual("111-111-1111", output["GuestPhone"]);
Assert.AreEqual("SomeAddress, SomeCity (SomeCountry)",
output["GuestAddress"]);
Assert.AreEqual("01/01/2016", output["CheckInDate"]);
Assert.AreEqual("02/01/2016", output["CheckOutDate"]);
Assert.AreEqual("Suite", output["RoomType"]);
Assert.AreEqual("1 Day", output["NumberOfDays"]);
Assert.AreEqual("1.00 €", output["TotalCost"]);
}

As you can see, in this test we pass to the Registration constructor the Room, the Guest and the BookingInformation objects properly configured and then we pass also a our Test Double that will get called and will record it’s inputs. After the method CheckOut gets called we have complete access to the information that it prepares and then passes over to the Print method. The SUT (System Under Test) doesn’t know that it’s talking to a test double so if the test passes we are sure that the method will work correctly in production when it will pass the dictionary to the object that will in fact print the invoice.

It’s not always that easy!

Sure, if you are working with some legacy code, chances are that your class doesn’t have the dependency that receives the indirect output nicely injected in the constructor. You could have something like this:

public class Registration2
{
private Room _room;
private Guest _guest;
private BookingInformation _booking;
public Registration2
(Room room, Guest guest,
BookingInformation <span class="hiddenGrammarError" pre=""><span class="hiddenGrammarError" pre="">booking)
{
_booking</span></span> = booking;
_guest = guest;
_room = room;
}
public void CheckOut()
{
Dictionary<string, string> invoiceInformation =
PrepareInvoiceData();
/////////////////////////////////////////////
Printer printer =
new Printer( /* PUT HUGE LIST OF PARAMETERS HERE */);
/////////////////////////////////////////////
printer.Print(invoiceInformation);
}
private Dictionary<string, string> PrepareInvoiceData()
{
////
///
return null;
}
}

How could you test the indirect output now?

Depending on the code base and how confident you are in refactoring it you could try different strategies like extracting the ugly part of your code to a protected method and then extend the class with a special that you use class just for testing. Another way to address this problem is to isolate your code wrapping the external dependency in a class that you can override like this:

internal interface IPrintWarpper
{
void Print(Dictionary<string, string> invoiceInformation);
}
internal class PrintWrapper : IPrintWarpper
{
private Printer printer;
public PrintWrapper()
{
Printer printer =
new Printer( /* PUT HUGE LIST OF PARAMETERS HERE */);
}
public void Print(Dictionary<string, string> invoiceInformation)
{
printer.Print(invoiceInformation);
}
}

Now you have isolated the dependency and have an interface that you can implement with your Test Spy

Now it’s your turn

Take a small function that has just one well-defined indirect output extract it and test the behavior YOUR code.

Also, don’t forget to share this post with your friends that have problems testing their code!

Author: Daniele Pozzobon

Daniele is an aspiring software craftsman with more that ten years of experience in the software industry. He is currently a consultant in the .Net space for a big insurance company, and previously have worked as a web dev in the manufacturing industry. He has experience with C#, Java, C++, PHP, Javascript, and lately has added some F# to the sauce.
He constantly annoys his friends by talking about software and is passionate about Agile methodologies, which gives him more opportunities to talk annoy his friends even more.
When there are no friends around to annoy, he blogs on CodeCleaners and in his free he time loves go hiking with his wife and two daughters.