A TDD Journey: 3- Mocks vs. Stubs; Test Frameworks; Assertions; ReSharper Accelerators

Test-Driven Development (TDD) involves the repetition of a very short development cycle that begins with an initially-failing test that defines the required functionality, and ends with producing the minimum amount of code to pass that test, and finally refactoring the new code. Michael Sorens continues his introduction to TDD that is more of a journey in six parts, by implementing the first tests and introducing the topics of Test doubles; Test Runners, Constraints and assertions

This is part 3 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 (a short introduction to TDD reasons and methods) and part 2 (implementing the first tests) before proceeding.

The code to date is shown immediately below. Points to review:

  • WidgetActivator is the class-under-test.
  • The WidgetActivator needs both a loader and a publisher to do its work.
  • The first test verifies that the loader is wired up correctly in the form of an WidgetLoader. Using an interface for the type makes it easy to swap in a testing version (a mock) of a WidgetLoader in the test shown, whereas production code will use a genuine WidgetLoader.
  • The second test verifies that the WidgetActivator uses its WidgetLoader to do something.
  • The moq mocking framework lets you check if a particular method was called on the mock with moq’s Verify method.

Now we introduce the IWidgetPublisher , which is analogous to the WidgetLoader. In the interests of brevity, from this point forward I am only going to show the relevant portions of the code rather than showing everything. So here we go!

TEST: Again start by creating a WidgetActivator . To compile we must supply an WidgetLoader argument. But this test does not care about an WidgetLoader so we use a stub for that. (Notice that when we pass in a stub, there is no final “.Object”, like we had to use with the mock object in the previous test.)

2019-img2C.gifTest Doubles

Here you see the notion of a stub mentioned in the commentary-and reflected in the variable name-yet it is still using the Mock class. The reason is that moq handles stubs as well as mocks. In part 2, you saw that moq provides two syntax choices to create mock objects: the Linq-to-Mocks approach, which is better suited for stubs and the traditional imperative syntax, which is better suited for mocks. Mocks and stubs are both more broadly described as test doubles, a term coined by Gerard Meszaros in his book xUnit Patterns. A test double is simply a test objects used in place of a real object in a test. On his web site, Meszaros has a detailed chart comparing and contrasting mocks and stubs, along with fakes and dummies in (what an eponymous coincidence!) a section entitled Mocks, Fakes, Stubs, and Dummies. Unfortunately, he quickly reveals that the nomenclature is haphazard at best, with different authors using different terms: a stub is sometimes called a mock, a dummy is sometimes called a stub (but at least a mock is always a mock :-). I mention that only so that as you do further reading on your own you are prepared to pay less attention to the names and more to the substance.

Briefly then, here is a good summary of mocks, fakes, stubs, and dummies according to Meszaros interpreted by Martin Fowler in Mocks Aren’t Stubs because he says it so well:

  • Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.
  • Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in-memory database is a good example).
  • Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what’s programmed in for the test…
  • Mocks are… objects pre-programmed with expectations [that] form a specification of the calls they are expected to receive.

2019-img32.gif

TEST: As I said, we do not care in this test about the loader so we used a stub. What we do care about is an IWidgetPublisher so let’s add a mock rather than a stub, just as we did in the first test, and also pass it to the WidgetActivator  constructor.

Generally speaking, I prefer to use the Mock-to-Linq syntax (i.e. Mock.Of<type>) for stubs and moq’s traditional syntax (new Mock<type>) for mocks as you see above. There is a lot of overlap in the capabilities of the two, so that rule is by convention not by necessity. I particularly like it, though, because anyone reading my tests will know which test doubles are important for a given test-the mocks rather than the stubs.

CODE: That completes the test; now we work on getting the production code to compile and the test to pass. This new test is quite analogous to the earlier WidgetLoader test, except now we need a two-argument constructor for WidgetActivator . But first, let’s add the new required interface.

A constructor change is one of many rote tasks where ReSharper really shines (and CodeRush and their ilk). Updating the constructor and adding a backing field for the IWidgetPublisher can be done with just a couple key strokes. With the cursor in the mockWidgetPublisher.Object text, Alt+Enter brings up this ReSharper “quick fix” menu:

2019-img2D.jpg

That default choice is what we want, so just press Enter to add it to the constructor’s signature, as you see below. Moving the cursor onto that new parameter in the constructor and again using Alt+Enter, ReSharper brings up the “quick fix” choices below and again, the first choice is the appropriate one, so Enter finishes up the code to match what you saw just above.

2019-img2E.jpg

CODE: Here are the changes ReSharper implemented.

TEST: Analogous to exercising the WidgetLoader, now we want the IWidgetPublisher to do some work.

CODE: To get a clean compile we add Publish to the IWidgetPublisher interface.

CODE: Now the Verify assertion fails-because we have not yet wired up the Publish method call. Add the call to Publish to make it pass.

That final line of code made our test turn green! But wait a minute-the first test is failing now! How do I know? Because whenever I get the code to compile I run all tests, not just the latest test.

2019-img2C.gifTest Runners

Visual Studio comes with a built-in test runner for unit tests, but it is only compatible with MSTest unit tests, not NUnit unit tests, as I prefer to use. Here is why:

#

Feature

MSTest

NUnit

1

Visual Studio support to run tests

2019-imgE.gifBuilt-in

Requires NUnit Test Adapter

2

Visual Studio test templates

2019-img11.gifBuilt-in

None

3

Tests runnable outside VS

No

2019-imgE.gif(NUnit GUI console)

4

Much faster startup time for each run

 

2019-imgE.gif

5

Fluent assertion interface

 

2019-imgE.gif2019-imgE.gif2019-imgE.gif2019-imgE.gif

6

Rich attribute set

 

2019-imgE.gif2019-imgE.gif2019-imgE.gif2019-imgE.gif

MSTest has a minor advantage in row 1, in that the test runner is built-in. But if you use ReSharper or NCrunch they provide built-in test runners as well-which are NUnit-compatible-so you would not even need the NUnit Test Adapter. MSTest also has a minor advantage in row 2, by having some project templates; however, test templates are not really a necessity as they are so simple to set up. The deal breakers to me, as indicated by the relative weightings in the table, are the fluent assertions and rich attribute set of NUnit. More details on those shortly.

Whichever unit test framework and ancillary tools you choose, you will have a test runner available in Visual Studio so it is a simple matter to re-run all tests as needed so you will be kept apprised of when your code changes have ripple effects into other tests.

2019-img32.gif

The test under development passes, as I stated, but now the previous test fails on the Execute call. That test never supplied an IWidgetPublisher so attempting to call Publish on a null object throws an exception. This is apparently exposing a weakness in our set of behaviors thus far: in essence, the code is saying that we do not expect null objects passed in but we have not codified that into a test. In actuality, that was a system design choice on my part. When I do dependency injection I prefer to use an IoC container, as I mentioned in part 2. One advantage of using such a container to automate DI over using manual injection is that no IoC containers that I am aware allow nulls to be passed in as a constructor dependency.

TEST: So we just need to go back and give the prior test an IWidgetPublisher to avoid getting this exception. Notice how this test uses a mock and a stub exactly the opposite of the latest test.

Now both tests pass!

Here is the first time we introduce the refactor step of the Red-Green-Refactor process introduced in part 1. We have now outfitted 3 of the 4 unit tests for the two-argument constructor; only the very first test is still using the one-argument version. So to make it a bit tidier, let’s add a stub to that first test so it, too, can use the two-argument form, allowing us to delete the one-argument constructor.

TEST: Add a stub to pass to the two-argument constructor.

CODE: Delete the one-argument constructor.

Run the tests again and they still pass, confirming that our refactor did not change the code’s behavior in any way. Whenever refactoring keep in mind the developer’s version of the Hippocratic Oath:

Cleanup your code-but do no harm!

Now that we have a loader and a publisher, the next most important behavior is that if there are no details for the loader to load, the Execute method should return false. In this test, I am using two stubs because neither of them is the focus of the test-here we are interested in what the Execute method is doing.

TEST: Create the basic test.

2019-img2C.gifConstraints and Fluent Assertions

The crux of this test is the assertion in the final line: the Assert.That() method call. This single method-albeit with a large number of overloads-is the method to use for most validation in NUnit tests. It has the general form:

The first argument is your actual result. The second argument is a Constraint object that specifies what about the result you are validating. This constraint-based model, introduced fairly recently with NUnit 2.4, is what provides the fluent API of NUnit. Here are a few other sample assertions possible with Assert.That (see the NUnit documentation for many more):

Earlier in this article I mentioned that NUnit’s fluent assertion interface weighed heavily in selecting NUnit as my choice of test framework. NUnit’s constraint-based model above provides this fluent interface (first introduced in 2005 by Martin Fowler). The key element to observe is the combination of method chaining (tying output of one method into the input of the next) and the readability that ensues due to the flow of text. As an example, above you see one Assert call that uses this constraint:  Is.EqualTo( 5).Within(15).Percent. That chains together 4 elements nicely so that the entire statement, in English, reads “Assert that 5.5 is equal to 5 within 15 percent.”

A fluent interface lets you just read your tests. Why is this useful? Consider these two assertions, one using MSTest and one using NUnit. Contrast their readability-literally, read them out loud-and you will see why a fluent interface is advantageous:

MSTest

Assert.IsNotNull(Players.Where(x => x.Name.Equals(“Cross”);

NUnit

Assert.That(Players, Has.Some.With.Property(“Name”).EqualTo(“Cross”);

If you can read your tests when you write them, so can other members of your team. (And so can you two weeks from now :-). They are that much easier to comprehend. One more example-this is how to check for an expected exception with MSTest:

And this is how to do the same thing with NUnit (actually this does even more; it also checks the message of the exception):

2019-img32.gif

CODE: Make it pass by adding a return value to Execute. Notice there is no attempt to make it behave “correctly” from the perspective of the system-we only care about making it behave correctly for this test.

If this is your first exposure to TDD, returning a hard-coded value may seem odd (or, let’s face it, just plain wrong!). That is obviously wrong in the sense that the Execute method clearly needs to return a semantically-valid result, not just “false”. In the long run, that is true-and Execute will evolve to return something better. But the rules of TDD (enumerated in part 1) require that you write the least amount of code to make the current test pass. In this instance, returning false is it; the test now passes! If you can contain your skepticism over the value and usefulness of just returning false, you will see how this approach bears fruit as the journey continues next time, in part 4!

For more articles like this, sign up to the fortnightly Simple-Talk newsletter.

Downloads

Tags: , ,

  • 12684 views

  • Rate
    [Total: 11    Average: 4.9/5]