• Skip to content
  • Skip to footer

Craftsmanship Counts

We're Hardcore About Software

  • Home
  • Courses
  • Blog
  • About
  • Contact Us

Eddie / December 16, 2016

How To Learn Test-Driven Development: Step 2 – Learn Test Doubles

Learn Test-Driven Development: Step 2 - Test Doubles

Once you learn JUnit, the next step to learn test-driven development is to begin learning about test doubles.

Remember, unit tests – which are foundational to test-driven development – require us to test a class in isolation. Achieving that isolation isn’t difficult, but there are some definite prerequisites.

This article builds on the last, in particular by using vocabulary defined there. If you did not read it and you’re finding that vocabulary used in this article is unfamiliar, go read that article and then come back here.

Assumptions

For this article, let’s assume that you are using some form of dependency injection to get collaborators into the test subject. We’ll also assume that dependencies are used through an interface.

Many people will use testing as a reason for creating interfaces. While should be a good motivation for most, it’s not actually the highest or most compelling reason.

A better reason to create interfaces is so that you can adhere to the Dependency Inversion Principle and thereby keep policy and mechanism separate. I say this is a higher and more compelling reason because separating policy and mechanism correlates directly to the long-term preservation of business value.

If you’re adding tests to a legacy codebase you may have collaborators that are represented by a concrete type though. In this case, your only real option is to extend the collaborator class to override behavior.

What is a Test Double?

So that we’re all on the same page, and because some of you may be undereducated about test doubles, let’s have a look at how I use the word.

A test double is a class whose sole purpose in life is to help ensure that the system being built works as expected. Depending on the type of test double, it may have no behavior or quite a bit of behavior. However, in all cases, if you looked at the class, we would agree that the test double has no place in production use.

Every test double should have a clear reason for existing though – it should facilitate some necessary part of testing one or more test subjects.

Since this is sounding awful hand-wavy (jazz hands, if you prefer), and I want it to be very concrete and understandable, let’s dig into the various types of test doubles. I think it’ll help a lot.

Types of Test Doubles

There are many different types of test doubles. Each achieves some testing goal. All can be simulated with a mocking framework.

The problem with mocking frameworks is that, if you need to test the same behavior of the same test subject in different ways, there can be a lot of setup needed to cause it to behave as expected. In these cases, writing a custom test double can bring simplicity and reduce duplication.

Custom test doubles shine particularly bright when you have a common interface with lots of different implementations that share a common set of collaborators. In this case, the same test doubles can be used across all tests – really giving you bang for your buck.

Test Double Type 1: The Dummy

A dummy test double matches the type of a parameter, but provides no useful behavior. Its sole purpose is just filling that slot in the parameter list.

When to Use a Dummy Test Double

A dummy can be used anytime you have an argument that you believe is not used.

How to Implement a Dummy Test Double

The simplest implementation of a dummy is the null value. After all, if the dummy is truly unused, no NullPointerException should be triggered.

You could also use an anonymous or named implementation of an interface which is defined to do nothing.

Additional Thoughts on Dummy Test Doubles

As mentioned above, if your expectation is that the dummy is never used, you may be better off using a different test double type. My personal recommendation is that you use a spy (see below) because doing so will allow you to verify that the test double is truly not called.

There’s a deeper thought here though. If you have a parameter that is unused, you should be asking why it is there to begin with. While there may be some legitimate cases for this, there aren’t many, and there’s a good chance that you would be well served to look at the design and refactor to avoid use of the parameter.

Test Double Type 2: The Fake

A fake is a bit more complex than a dummy. It has some form of working implementation, but isn’t something you’d ever use in production.

When to Use a Fake Test Double

Fakes can be useful when the real implementation is either not available or would significantly slow-down the tests. The canonical use case for a fake is the hand-written, in-memory database.

How to Implement a Fake Test Double

The implementation of a fake will vary depending depending on what the real collaborator would do and what testing needs you are trying to satisfy.

In the case of a database, your goals are to satisfy the needs of a service layer – inserting data and then being able to retrieve it. Or, perhaps, throwing some sort of exception if what you’re looking for isn’t there.

Additional Thoughts on Fake Test Doubles

The more expensive calling a real implementation is, the less you will want to use it and the more you’ll want to replace it with something else.

Fake test doubles are really useful for replacing all sorts of external dependencies. For example, consider a situation where you’re calling an external service over HTTP. While this might be great in production, having that dependency in your unit tests will not only slow them down, but will cause your entire build to fail if the team that maintains that service takes it down for maintenance.

Test Double Type 3: The Stub

The job of a stub is to return canned answers that enable you to test specific outcomes within a test subject.

When to Use a Stub Test Double

If your test subject has any logical branching, stubs are essential. The canned answers they provide allow you to ensure that those logical branches are reachable and testable.

How to Implement a Stub Test Double

It is common for stubs to be written with a set of canned answers. However, if the stub has potentially broad applicability, it may be better if it is built in a way that allows it to be programmed on a per-test-case basis.

Additional Thoughts on Stub Test Doubles

The more complex the requirements you are wanting to stub, the more you may want to consider a mocking framework. We’ll talk about those in an upcoming article.

Test Double Type 4: The Spy

A spy test double tracks how it is called. This could include metrics as simple as the number of calls or as complex as preserving parameters used during invocation.

When to Use a Spy Test Double

Spies should be used when you need more information about how a collaborator is called.

How to Implement a Spy Test Double

Simple spy implementations may be a variation on the dummy (described above). More complex ones will track all parameters and invocation counts.

Additional Thoughts on Spy Test Doubles

A trick I like to use is to create the spy following the Decorator Pattern. This allows me to use the spy in combination with other test double types, such as a fake (described above).

Test Double Type 5: The Mock

Mocks are typically more complex than other types of test doubles, and may well combine elements of multiple other test double types.

When to Use a Mock Test Double

Mocks are useful when you need complex stubbing behavior, or when you want to combine elements of both stubbing and spying.

How to Implement a Spy Test Double

Mocks may be hand-written or created by using a mocking framework.

Additional Thoughts on Mock Test Doubles

While most people tend to use a mocking framework to create mocks, hand-writing them can be a useful approach too. For example, if the mock is commonly used in the same way, hand-writing the mock may reduce redundancy and improve readability.

As mentioned above, I find I can often get great utility from a combination of a spy – implemented as a decorator – and a stub.

Wrapping It Up

When you use a particular test double – and whether or not you choose a framework to help – can be highly situational. If, for example, you find that you have little repetition among tests, a mocking framework might provide a lighter approach.

If, on the other hand, you are seeing a lot of repetitive use of a mocking framework being applied the exact same way, you should consider creating hand-written test doubles of the appropriate type and using them instead. Doing so can greatly simplify your tests making it easier to understand and maintain them.

That’s it for this now! Until next time, this is Eddie Bush with Craftsmanship Counts reminding you to keep your tests passing and your code clean!

Filed Under: Featured

Save 52% From Black Friday to Cyber Monday!

Looking for a Clean Architecture course that covers more than theory? Check out Java Clean Architecture by Example! Click Here to Save 52% Through Cyber Monday!

Weekly Newsletter

Our number one goal is to help you improve a little bit each time we press publish. If that sounds like fun to you, just fill out the following form and click 'Yes! Sign Me Up!'

By joining the Craftsmanship Counts Newsletter, you agree to our Privacy Policy.

Reader Interactions

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Footer

Contact Us

Craftsmanship Counts
13364 S 4328
Chouteau, OK 74337

918-373-3594

About Us

Craftsmanship Counts is a botique consultancy offering Agile leadership, development, and clean coding services.

Learn More

Follow Us

  • Google+
  • LinkedIn
  • Twitter

© 2016 Craftsmanship Counts, LLC - All Rights Reserved

  • Privacy
  • Anti-Spam