DEV Community

Jan Van Ryswyck
Jan Van Ryswyck

Posted on • Originally published at principal-it.eu on

Inside-Out and Outside-In TDD

Test-Driven Development is a discipline that exists for about two decades now. Unfortunately, to this very day, it is still not without controversy. Most professional developers know that writing some form of automated tests can be quite beneficial for any type of codebase. What still seems to be quite controversial is whether to write a test before or after the production code has been laid out. This discussion seems to stir its head every other day on many discussion forums and on social media.

When I use the term TDD, I mean the repeating process of first writing a failing test, then writing as little production code as possible to make the test pass, after which the important step of refactoring the code ensues. This process is also commonly referred to as “Red, Green, Refactor”.

Some people firmly follow this mantra of “Red, Green, Refactor”. Others don’t like to follow this strict process for whatever reason and prefer to write tests after they’ve completed the implementation. Personally I like to write tests before the production code, and I highly encourage anyone to adopt this practice if they haven’t already.

Nevertheless, I would like to touch on two different approaches to Test-Driven Development that are practiced throughout the world of software development, namely:

  • Inside-Out TDD
  • Outside-In TDD

Inside-Out TDD

As its names implies, this approach allows us to start with the smallest unit of code - exercising either an individual class or module - by following the “Red, Green, Refactor” cycle. During this process, the design of theimplementation happens during the “Refactor” step. This step is quite important and becomes more involved compared to the “Red” and “Green” steps. Each entity of the system is created in a TDD fashion using solitary tests until the whole feature is built up. Then a few sociable tests are added to verify that all the parts are working together as expected.

Inside-Out TDD is basically the approach where you start at the bottom of the the test pyramid and work your way up.

The Inside-Out Test-Driven-Development process

The most notable advantage by first focusing on the individual parts of the system is the ability to work in very small increments. This also enables that the development work can be parallelized within a software team.

The downside of Inside-Out TDD is that by initially focusing on the individual parts, there’s a higher risk of these entities not working together correctly with the possibility of rework.

Outside-In TDD

This approach focuses on creating a complete flow between the larger parts of the system right from the start. All the entities that make up a feature of the system are being created from the get-go, immediately verifying the wiring and interactions between them. The design of the system happens upfront during the “Red” step of “Red, Green, Refactor”. This results in the “Refactor” step becoming much more shallow. The different parts that make up a feature of the system are put in place while writing a failing sociable test. Such a thin slice of real functionality is also referred to as a walking skeleton (see Growing Object Oriented Software Guided By Tests). This failing sociable test serves as a beacon, making sure that no implementation is being forgotten.

The Outside-In Test-Driven-Development process

The first test being written usually exercises a controller or a service at the system boundary as the starting point. A sociable test is usually employed here instead of a solitary test. Some parts of the code need to be swapped out by fake implementations that mimic the behaviour of the real-world implementations.

The process of putting a spike through the implementation of the system

When every piece of the puzzle is in place, solitary tests are then used to further flesh out the concrete implementations of these individual classes or modules.

Outside-In TDD is basically the approach where you start at the top of the the test pyramid and work your way down.

The advantage of this approach is that it feels more exploratory, and is ideal for those kinds of situations where the high-level parts of the system are known without committing to the more fine-grained implementation details. This results in a “think like the client” mindset well before we start thinking as a software developer.

The downside of Outside-In TDD is that the design of the larger feature and its different parts should be known right from the start as opposed to driving the design of the smaller parts of the system. This usually takes significantly more time to write a first failing sociable test.

Conclusion

One might come to the conclusion that it’s somehow important to choose one approach over the other. However, this is definitely not the case. Please note that Inside-Out TDD and Outside-In TDD are not mutually exclusive. There’s no point in choosing one approach over the other and rigorously sticking to a particular choice. We should practice and master both ways of writing automated tests in order to develop a “gut instinct” for applying a certain approach.

Top comments (0)