Unit Testing And Seams

One of the topics I found very interesting form the Art Of Unit Testing was seams. I wanted to write a blog post to explore that a little bit.

What is a Seam?

Seams are places in your code where you can plug in different functionality …

Art of Unit Testing, 2nd edition page 54

Seams are a technique to help us test hard-to-test code. They allow us to replace production functionality with different functionality while testing. We typically do this by replacing a real dependency with a test double or mock. We do this because the real dependency is something we can’t directly control from the test code. Examples include files, databases, network communications.

How do I add a seam into my program?

There are various ways to add seams to your program. They all revolve around inheritance. Adding a seam is simply exposing an object so that it can be replaced with a child object. Here are 2 common methods.

Dependency Injection

The simplest way to add a seam is to use regular old dependency injection. In this case, our Software Under Test (SUT) is composed of an interface for a Depended On Component (DOC). To add a seam all we have to do is provide a property node to set the DOC. Now we can specify either the real DOC or a mock object or test double.

Our SUT is composed of the DOC.

In our test, we can use the property node to set the SUT to use a test double or mock instead of the real DOC. Then after that, every time the SUT calls a method on the DOC it will use the test double or mock instead.

In our test before we call the method(s) we want to test, we need to inject the Mock or Test Double.

A real-world example might be a driver for an instrument. It is probably composed of a serial port. You could easily compose the instrument of a serial interface instead. Then at test time, you could easily sub in a mock serial port.

As A Method Parameter

There is an alternative to having the SUT be composed of the DOC. The DOC can be passed in as a parameter to a method. This can work well when using the Strategy Pattern. In the test, we just pass in Mock Object or Test Double instead of the concrete class used in production.

An alternative to traditional dependency injection is using method parameters. Here when we call the method we want to test, we pass in the Mock Object or Test Double as a parameter.

A real-world example might be an object that gets saved to a file. Since the file is only really used when saving (and maybe loading) the object, it doesn’t make sense to use composition. The save method could take a generic file interface as a parameter. Then at test time, you could bypass the file system by injecting a mock object or test double.

4 Comments on “Unit Testing And Seams

  1. I’d rather say, that seams are kind of a bit better defined in M.C. Feather’s “Working Efficiently with legacy code”:
    ” SEAM: A seam is a place where you can alter behavior in your program without editing in that place”.

    There is completely different approach when you work on new clean code within a clean architecture preferably even implementing TTD, where you can plan ahead how you will design and implement your seams; in contrast to a situation when you just inherit a spaghetti code and you need to sweat-out to find a suitable place for any seam.

    In the book I have mentioned, there is a whole chapter dedicated to the topic of seams, as in legacy code (understood as code without tests) creating seams is an art. It can be an interesting complimentary material to this great introduction to seams made by Sam.

    • Not surprised to hear you mention that book (again). It is on my desk waiting to be read. Every time I talk to you, it moves up in the list of books to read. Thanks for mentioning that for anyone who hasn’t heard of it. By the way, you can hear Michael Feathers talk about it on the Maintainable Podcast. Very much worth listening to.

    • Michael’s book is a good one and worth digesting more than once. I do find it is heavily focused on the procedural / OOP space but there are a lot of ideas that can be readily applied into other paradigms as well.

      • Glad you liked the book. Another reason to move it further up my list. So many books, so little time.

Leave a Reply

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