Find the Seam

Learn about Seams and Pebbles with examples and learn how to redirect the code execution.

Test doubles are a specific version of a more general technique for working with legacy code, which involves finding seams in the code and exploiting them to make testing the legacy functionality possible.

Seams

A seam is a place where we can change our application’s behavior without changing the code. A test double acts as a seam because adding the test double, which happens in the test, changes the behavior of the code by mandating a specific response to a method call without executing the method. Again, the behavior of the method under test changes in the test environment without affecting behavior in production and without changing the existing development code.

It sounds magical, but the basic idea is simple, and Ruby makes it easy to execute. We redirect a method call from its intended target to some other code that we want to run during tests. A test double does this by replacing the entire method call with a return value, but the generic form lets us do anything we want instead of the method call.

Pebbles

We might create our own object if we wanted a side effect that a mock package wouldn’t normally provide, such as diagnostic logging. (Feathers calls this a pebble: a fake object that logs its own path through the code.) Alternatively, we might want more elaborate processing of arguments or state than a mock can easily provide, to re-create the output of a web service our application depends on, for example. (Even if the test-double library allows us to pass an arbitrary block as the result of the stubbed call, it’s often more readable to create our own object).

Example

Let’s take some sample Ruby code that we want to test. In this sample, flit_server is an object in our system representing an internal server, and those innocent-looking calls are genuine external service calls to a real server that exists in production but not in the test:

Get hands-on with 1200+ tech skills courses.