Manage test fixtures for fast and reliable in-memory tests

Why Don’t You Take ‘Given’ in BDD Seriously?

Martin Fowler’s Object Mother Pattern Revisited

This will be clear once you have read this post.

Similar work

I have struggled to find sources which explain how to properly handle initial context. For in-memory, isolated tests developers tend to use a mocking framework, setting up an entirely new set of mocks for each and every test. For end-to-end integration tests, it’s common to have a test environment with a huge test database, possibly containing a washed version of production data.

Background

There is an example of how to implement the Object Mother pattern in a paper by Peter Schuh and Stephanie Punke. While they make a good case, one quote in the paper troubles me,

  • Dependencies are injected into constructors.

Where is the code?

I call myself a developer and I have not written a single line of code so far. Shame on me, here we go.

We have two microservices, of which one is responsible for users and another is responsible for invoices. Each of the microservices own a database for persisting business objects. We will target the Users microservice.
From the point of view of our tests, we care about data on users, addresses and invoices, but not about how such data is handled in our external dependencies.

Conclusion

The concept of an Object Mother, a common source of test fixtures, was born in the context of unit testing and XP.

  • generically builds test fixtures from boundary values declared to the DI container.
  • Process. I have described the end-result, i.e. how tests should look like and how they should interact with the Object Mother, but I have not described the process for getting there. Is it TDD, and if so — is it inside-out or outside-in TDD, or an integrated adoption of those two approaches? (Spoiler alert — it’s largely like the latter, we strive for continuous testing.)
  • Systematic test analysis and documentation of the reasoning behind a set of test cases. I have only hinted at the possibility for visible functional coverage and confidence. (Spoiler alert — it is possible.)
  • The role of testers. If developers can write tests at all levels of a test pyramid, do we then still need testers? (Spoiler alert — yes, we still need testers.)
  • Using DI. I have described how we use DI in order to handle the life-cycle of test fixtures and also in order to declare and discover boundary values. But there is more to this topic. Using the composition root of production code in tests, then overriding declarations for a few mocks, is core to the approach. In AspNet.Core it’s the key to covering middleware and background jobs, if you use CQRS it’s how you reuse commands and readers from production code.
  • Practical experience. We have used the principles described in this post for several years in Saxo Bank, the last few years extensively on our OpenAPI. Our experience is similar to Microsoft’s — we now have faster and more reliable tests which allow us to release with cloud cadence.

Resources

Martin Fowler: ObjectMother.
Peter Schuh and Stephanie Punke: ObjectMother, Easing Test Object Creation in XP.
J B Rainsberger: Integration Tests Are A Scam HD.
Destroy All Software: Functional core, Imperative Shell.
Matt Diephouse: Test Doubles Are A Scam.
Justin Searls: Please don’t mock me.
Destroy All Software: Boundaries.
Mark Seemann: Composition Root.
Monty Python: Let’s not bicker and argue about who killed who.
Microsoft: Shift Left to Make Testing Fast and Reliable.
Dan North: Behavior Modification.
Brian Elgaard: Sample code for this post.
Wikipedia: Command–query separation.
Andrew Lock: Should you unit-test API/MVC controllers in ASP.NET Core?
Brian Elgaard: Multiple Asserts in a Single Unit Test method.
Brian Elgaard: Even More Asserts in a Single Unit Test Method.
Wikipedia: Cyclomatic complexity.
LeanTest.Net: Lean Testing in C#.
LeanTest.Net: Leantest source.
LeanTest.Net: nuGet Packages.
Doug Klugh: London vs Chicago.
Saxo Bank OpenAPI Developer Portal.
Liz Keogh: Scenarios using custom DSLs.

I write about life, universe and software development.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store