A TDD Journey: 6- Mini-Factory Pattern; Don’t Care Terms

Michael Sorens wraps up his TDD journey by discussing a number of tools and techniques, such as the mini-factory design pattern and the 'don't care' capability, that can be used in TDD (Test-Driven Development)t to increase the likelihood that you can approach 100% code-coverage.

This is part 6 of our exploration into practicing hands-on TDD. Unlike most of my multi-part series, it is not advisable to join this one in the middle. So if you are arriving fresh, please go back and review part 1 for an overview of TDD and subsequent parts that both built out our tests & code and introduced ancillary concepts and techniques crucial to the TDD approach.

Here is a summary of the behaviors we have implemented for our WidgetActivator thus far:

Hearken back to part 1 for a discussion of how test-driven development is just behavior-driven development in disguise. Thinking of tests as behaviors instead, it is much easier to decide what code to write next: what is the next most important behavior your system needs to be able to do? Let’s take a look.

TEST: The loader and publisher are barebones, so far, not actually being given any data to process. So let’s first introduce an IAddressProvider-by way of a test, of course!-to provide an address from which the loader will load. (This whole test is new, of course, so I am highlighting the significant portions here.)

CODE: There are several compile errors here. First we need to create the IAddressProvider interface containing a GetAddress method.

We then need to adjust the WidgetActivator to accept an IAddressProvider. That is done with a single keystroke using ReSharper, as was demonstrated in part 3:

2019-img39.jpg

But attempting to apply that quick fix, ReSharper then asks me what to do about the current uses of the constructor-it is used, in fact, in all of our tests:

2019-img3A.jpg

ReSharper gives you a choice of actions for each one, but often none of those choices is ideal. Whichever you choose, you likely have to revisit each test method and redress it. You saw this already when we went from a one-argument constructor to a two-argument constructor. It is more cumbersome to deal with going yet again to a three-argument constructor. So let’s take a look at a different approach, a useful design pattern to make this much less painful.

For the moment I am going to leave the constructor as a two-argument constructor, and comment out the new test so the existing code will compile. That way the refactoring I am about to do can be easily checked for integrity (by ensuring all current tests still pass when done).

2019-img2C.gif Mini-Factory Pattern

I am going to introduce a mini-factory to create WidgetActivators in the form of a single method in the test class (it is the last method in the code sample below). The mini-factory lets you supply an WidgetLoader and an IWidgetPublisher but allows both to be optional. If you do not supply one, a simple stub is automatically used in its place. In the code here, I have commented out rather than deleting deprecated lines so you can see the “before” and “after”. So here is the entire test class, with the mini-factory, CreateWidgetActivator, in place:

In the first test the loader was just a default mock object, which is now handled automatically by the factory so we no longer have to pass that in. But because we want to pass the second parameter while omitting the first, we use C#’s named arguments. This lets you specify any of the optional parameters by using its name:

The second test, on the other hand, needs both loader and publisher to behave a certain way so both are passed in. I still use the factory method, however, even though there is no savings in the test because it helps isolate the use of the WidgetActivator constructor to a single place in the test code, a good design practice. Similarly with the third and fourth tests. So there is not a lot of code reduction in the tests, but you will see the utility of this mini-factory in a moment.

2019-img32.gif

TEST: Let’s re-introduce that new test we started to add before the interlude above, now within the context of this mini-factory. We introduce a new parameter to the factory method, an addressProvider, and that is the only one we care about, so we used a named argument.

TEST: Adding that parameter to the factory method still necessitates adjusting a signature, but this time it is the signature of the factory method in the test class. By just adding one line to the factory, all the other tests are still working:

TEST: Now we can finally focus on the task of turning the red test to green. We start by hooking up the parameter we just added in the factory.

CODE: That causes a compile error, because the WidgetActivator constructor does not handle an IAddressProvider yet. Now applying ReSharper’s Add Parameter adjusts the constructor signature to accept the parameter.

CODE: Applying ReSharper’s Introduce and initialize field on that parameter makes that parameter available within the class.

With this last tweak we now have code that compiles. And reviewing all tests shows just one that is failing-the very test we are working on.

Add a call to the GetAddress method on the IAddressProvider interface to make the test go green:

But the test passing is not the most interesting point here. The factory method was implemented to achieve two particular goals: centralize the call to the WidgetActivator constructor to a single spot and provide defaults for all dependencies. Those two together mean that (a) adding dependencies to the signature of that constructor needs to happen in just one place, and (b) calls to the factory do not have to change to accommodate new dependencies to the constructor. The net result: you do not have to edit some or even all of your previous tests, as you would have to without the factory.

TEST: So we have an address; now we need to use it.

CODE: To allow the above to compile, first we need to adjust the IAddressProvider interface to return a value from the GetAddress method.

CODE: Then we need to adjust the WidgetLoader interface to accept a value in the Load method.

TEST: That last change will, however, cause repercussions in several other tests that we must go back to fix before the compile completes. In these other tests we do not care what was passed to the Load method so specify a “don’t care” with It.IsAny. Here is a fix to one of the tests; the others require the same update:

CODE: Finally, the class under test must also be modified to satisfy our new test:

And that brings us back to all tests passing:

2019-img68.gif

2019-img2C.gif Don’t Care Terms

We introduced the “don’t care” term in a moq SetUp call just above: It.IsAny<string>(). But such “don’t care” terms are not restricted to just SetUp calls. They may be used in most any Moq method. In this latest test case we verified that a method was called with a specific value that was passed in. But another common case is verifying that a method was called at all, regardless of the arguments. That is, instead of this:

…you might just use this if desired:

And you are not limited to simple, built-in types with It.IsAny; it is a standard generic type It.IsAny<T> so you could use your complex objects (It.IsAny<MyContractType>) or even your own generic types (It.IsAny<MyDetail<MyContractType>>). For cases where your type may be unwieldy you could even use  something like It.IsAny<object> or It.IsAny<object[]>.

2019-img32.gif

TEST: Just as the loader needs an address, so does the publisher. Notice that for the WidgetLoader here I use a “don’t care” because this test is about the WidgetPublisher.

CODE: To get that to compile we modify the Publish method on the interface to take a parameter.

TEST: That, however, breaks several tests that were not expecting a parameter. We go back and introduce a “don’t care” in those tests, be it in the SetUp method or the Verify method. Here are two of the four tests that need the patch.

CODE: Finally, we introduce the parameter in the class under test, giving us a clean compile again, as well as the new test (Execute_uses_an_address_to_publish_widget) now passing.

Adding the mini-factory design pattern and the don’t care capability to test parameterization, ReSharper quick fixes, and the other tools and techniques amassed thus far, you should have quite the arsenal to assist your own TDD development efforts. What is most fascinating about TDD to me is this: looking at the Execute method just above, every token is there to satisfy a test. There is no fat, no excess. We have, by the nature of TDD, 100% coverage for this code. Note, however, that I am not claiming that 100% code coverage is always easy or practical. But you do have complete coverage for those bits that you can build with TDD. If you found this TDD series useful, be sure to spread the word! If interest warrants, there is always more to explore: code coverage, refactoring, arrange-act-assert, equivalence partitioning, boundary value analysis, queuing theory, and more…