- Part 1: Trials and Tribulations of TDD
- Part 2: Naming Tests; Mocking Frameworks; Dependency Injection
- Part 3: Mocks vs. Stubs; Test Frameworks; Assertions; ReSharper Accelerators
- Part 4: Tests as Documentation; False Positive Results; Component Isolation
- Part 5: Tests vs. Code; Refactor Friendliness; Test Parameterization
- Part 6: Mini-Factory Pattern; Don’t Care Terms
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:
1 2 3 4 5 6 |
WidgetActivatorTest: Execute_returns_false_when_loading_fails_and_then_publishing_succeeds Execute_returns_true_when_loading_succeeds_and_then_publishing_succeeds Execute_returns_false_when_publishing_fails_after_loading_succeeds Execute_returns_true_when_publishing_succeeds_after_loading_succeeds Execute_only_publishes_if_loading_succeeds |
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.)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[Test] public void Execute_gets_an_address_from_which_to_load_a_widget() { var mockAddressProvider = new Mock<IAddressProvider>(); var stubWidgetLoader = Mock.Of<IWidgetLoader>(); var stubWidgetPublisher = Mock.Of<IWidgetPublisher>(); var activator = new WidgetActivator( stubWidgetLoader, stubWidgetPublisher, mockAddressProvider.Object); activator.Execute(); mockAddressProvider.Verify(x => x.GetAddress(), Times.Once()); } |
CODE: There are several compile errors here. First we need to create the IAddressProvider interface containing a GetAddress method.
1 2 3 4 |
public interface IAddressProvider { void GetAddress(); } |
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:
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:
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).
1 2 3 4 5 6 7 8 9 10 11 12 |
//public void Execute_gets_an_address_from_which_to_load_a_widget() //{ // var mockAddressProvider = new Mock<IAddressProvider>(); // var stubWidgetLoader = Mock.Of<IWidgetLoader>(); // var stubWidgetPublisher = Mock.Of<IWidgetPublisher>(); // var activator = new WidgetActivator( // stubWidgetLoader, stubWidgetPublisher, mockAddressProvider.Object); // // activator.Execute(); // // mockAddressProvider.Verify(x => x.GetAddress(), Times.Once()); //} |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
public class WidgetActivatorTest { [Test] public void Execute_returns_false_when_loading_fails_and_then_publishing_succeeds() { //var stubWidgetLoader = Mock.Of<IWidgetLoader>(); var stubWidgetPublisher = Mock.Of<IWidgetPublisher>( x => x.Publish() == true ); //var activator = new WidgetActivator(stubWidgetLoader, stubWidgetPublisher); var activator = CreateWidgetActivator(widgetPublisher: stubWidgetPublisher); var result = activator.Execute(); Assert.That(result, Is.False); } [Test] public void Execute_returns_true_when_loading_succeeds_and_then_publishing_succeeds() { var mockWidgetLoader = new Mock<IWidgetLoader>(); mockWidgetLoader .Setup(x => x.Load()) .Returns(() => true); var stubWidgetPublisher = Mock.Of<IWidgetPublisher>( x => x.Publish() == true ); //var activator = new WidgetActivator(mockWidgetLoader.Object, stubWidgetPublisher); var activator = CreateWidgetActivator(mockWidgetLoader.Object, stubWidgetPublisher); var result = activator.Execute(); Assert.That(result, Is.True); } [Test] public void Execute_returns_false_when_publishing_fails_after_loading_succeeds() { var mockWidgetPublisher = new Mock<IWidgetPublisher>(); mockWidgetPublisher .Setup(x => x.Publish()) .Returns(() => false); var stubWidgetLoader = Mock.Of<IWidgetLoader>( x => x.Load() == true ); //var activator = new WidgetActivator(stubWidgetLoader, mockWidgetPublisher.Object); var activator = CreateWidgetActivator(stubWidgetLoader, mockWidgetPublisher.Object); var result = activator.Execute(); Assert.That(result, Is.False); } [Test] public void Execute_returns_true_when_publishing_succeeds_after_loading_succeeds() { var mockWidgetPublisher = new Mock<IWidgetPublisher>(); mockWidgetPublisher .Setup(x => x.Publish()) .Returns(() => true); var stubWidgetLoader = Mock.Of<IWidgetLoader>( x => x.Load() == true ); //var activator = new WidgetActivator(stubWidgetLoader, mockWidgetPublisher.Object); var activator = CreateWidgetActivator(stubWidgetLoader, mockWidgetPublisher.Object); var result = activator.Execute(); Assert.That(result, Is.True); } [TestCase(true, 1)] [TestCase(false, 0)] public void Execute_only_publishes_if_loading_succeeds(bool loaderSuccess, int callCount) { var stubWidgetLoader = Mock.Of<IWidgetLoader>( x => x.Load() == loaderSuccess ); var mockWidgetPublisher = new Mock<IWidgetPublisher>(); //var activator = new WidgetActivator(stubWidgetLoader, mockWidgetPublisher.Object); var activator = CreateWidgetActivator(stubWidgetLoader, mockWidgetPublisher.Object); activator.Execute(); mockWidgetPublisher.Verify(x => x.Publish(), Times.Exactly(callCount)); } private WidgetActivator CreateWidgetActivator( IWidgetLoader widgetLoader = null, IWidgetPublisher widgetPublisher = null ) { return new WidgetActivator( widgetLoader ?? Mock.Of<IWidgetLoader>(), widgetPublisher ?? Mock.Of<IWidgetPublisher>() ); } } |
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:
1 |
var activator = CreateWidgetActivator(widgetPublisher: stubWidgetPublisher); |
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.
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.
1 2 3 4 5 6 7 8 9 10 |
[Test] public void Execute_gets_an_address_from_which_to_load_a_widget() { var mockAddressProvider = new Mock<IAddressProvider>(); var activator = CreateWidgetActivator(addressProvider: mockAddressProvider.Object); activator.Execute(); mockAddressProvider.Verify(x => x.GetAddress(), Times.Once()); } |
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:
1 2 3 4 5 6 7 8 9 10 11 |
private WidgetActivator CreateWidgetActivator( IWidgetLoader widgetLoader = null, IWidgetPublisher widgetPublisher = null, IAddressProvider addressProvider = null ) { return new WidgetActivator( widgetLoader ?? Mock.Of<IWidgetLoader>(), widgetPublisher ?? Mock.Of<IWidgetPublisher>() ); } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 |
private WidgetActivator CreateWidgetActivator( IWidgetLoader widgetLoader = null, IWidgetPublisher widgetPublisher = null, IAddressProvider addressProvider = null ) { return new WidgetActivator( widgetLoader ?? Mock.Of<IWidgetLoader>(), widgetPublisher ?? Mock.Of<IWidgetPublisher>(), addressProvider ?? Mock.Of<IAddressProvider>() ); } |
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.
1 2 3 4 5 6 7 8 |
public WidgetActivator( IWidgetLoader widgetLoader, IWidgetPublisher widgetPublisher, IAddressProvider addressProvider) { _widgetLoader = widgetLoader; _widgetPublisher = widgetPublisher; } |
CODE: Applying ReSharper’s Introduce and initialize field on that parameter makes that parameter available within the class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class WidgetActivator { private readonly IWidgetLoader _widgetLoader; private readonly IWidgetPublisher _widgetPublisher; private readonly IAddressProvider _addressProvider; public WidgetActivator( IWidgetLoader widgetLoader, IWidgetPublisher widgetPublisher, IAddressProvider addressProvider) { _widgetLoader = widgetLoader; _widgetPublisher = widgetPublisher; _addressProvider = addressProvider; } } |
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:
1 2 3 4 5 6 7 8 9 10 |
public bool Execute() { _addressProvider.GetAddress(); var success = _widgetLoader.Load(); if (success) { success &= _widgetPublisher.Publish(); } return success; } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[Test] public void Execute_uses_an_address_to_load_widget() { var expectedAddress = "test address"; var stubAddressProvider = Mock.Of<IAddressProvider>( x => x.GetAddress() == expectedAddress); var mockWidgetLoader = new Mock<IWidgetLoader>(); var activator = CreateWidgetActivator( mockWidgetLoader.Object, addressProvider: stubAddressProvider); activator.Execute(); mockWidgetLoader.Verify(x => x.Load(expectedAddress), Times.Once); } |
CODE: To allow the above to compile, first we need to adjust the IAddressProvider interface to return a value from the GetAddress method.
1 2 3 4 |
public interface IAddressProvider { string GetAddress(); } |
CODE: Then we need to adjust the WidgetLoader
interface to accept a value in the Load method.
1 2 3 4 |
public interface IWidgetLoader { bool Load(string address); } |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[Test] public void Execute_returns_true_when_loading_succeeds_and_then_publishing_succeeds() { var mockWidgetLoader = new Mock<IWidgetLoader>(); mockWidgetLoader .Setup(x => x.Load(It.IsAny<string>())) .Returns(() => true); var stubWidgetPublisher = Mock.Of<IWidgetPublisher>( x => x.Publish() == true ); var activator = CreateWidgetActivator(mockWidgetLoader.Object, stubWidgetPublisher); var result = activator.Execute(); Assert.That(result, Is.True); } |
CODE: Finally, the class under test must also be modified to satisfy our new test:
1 2 3 4 5 6 7 8 9 10 |
public bool Execute() { var address = _addressProvider.GetAddress(); var success = _widgetLoader.Load(address); if (success) { success &= _widgetPublisher.Publish(); } return success; } |
And that brings us back to all tests passing:
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:
1 |
mockWidgetLoader.Verify(x => x.Load(expectedAddress), Times.Once); |
…you might just use this if desired:
1 |
mockWidgetLoader.Verify(x => x.Load(It.IsAny<string>()), Times.Once); |
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[]>
.
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
[Test] public void Execute_uses_an_address_to_publish_widget() { var expectedAddress = "test address"; var stubAddressProvider = Mock.Of<IAddressProvider>( x => x.GetAddress() == expectedAddress); var stubWidgetLoader = Mock.Of<IWidgetLoader>( x => x.Load(It.IsAny<string>()) == true); var mockWidgetPublisher = new Mock<IWidgetPublisher>(); var activator = CreateWidgetActivator( stubWidgetLoader, mockWidgetPublisher.Object, stubAddressProvider); activator.Execute(); mockWidgetPublisher.Verify(x => x.Publish(expectedAddress), Times.Once); } |
CODE: To get that to compile we modify the Publish method on the interface to take a parameter.
1 2 3 4 |
public interface IWidgetPublisher { bool Publish(string address); } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
[Test] public void Execute_returns_true_when_loading_succeeds_and_then_publishing_succeeds() { var mockWidgetLoader = new Mock<IWidgetLoader>(); mockWidgetLoader .Setup(x => x.Load(It.IsAny<string>())) .Returns(() => true); var stubWidgetPublisher = Mock.Of<IWidgetPublisher>( x => x.Publish(It.IsAny<string>()) == true ); var activator = CreateWidgetActivator(mockWidgetLoader.Object, stubWidgetPublisher); var result = activator.Execute(); Assert.That(result, Is.True); } [TestCase(true, 1)] [TestCase(false, 0)] public void Execute_only_publishes_if_loading_succeeds(bool loaderSuccess, int callCount) { var stubWidgetLoader = Mock.Of<IWidgetLoader>(x => x.Load(It.IsAny<string>()) == loaderSuccess); var mockWidgetPublisher = new Mock<IWidgetPublisher>(); var activator = CreateWidgetActivator(stubWidgetLoader, mockWidgetPublisher.Object); activator.Execute(); mockWidgetPublisher.Verify(x => x.Publish(It.IsAny<string>()), Times.Exactly(callCount)); } |
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.
1 2 3 4 5 6 7 8 9 10 |
public bool Execute() { var address = _addressProvider.GetAddress(); var success = _widgetLoader.Load(address); if (success) { success &= _widgetPublisher.Publish(address); } return success; } |
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…
Load comments