Published March 8, 2020
by Doug Klugh
A Fresh Start
Define the state of your test environment by designing and building a test fixture that supports a single run of a single test. Build a Transient Fixture when its lifetime should persist no longer than the duration of the test method and is initialized prior to each method. Building a Persistent Fixture that survives the life of the test must be torn down within the test method to avoid side effects and keep the fixture fresh.
A Transient Fresh Fixture is one that is created and destroyed within every test. This type of fixture is particularly easy to setup in JUnit using either a constructor or setup method (using the @Before attribute). JUnit will invoke either one (or both) before each test method. This type of fixture is transient because the lifetime of the fixture persists only for the duration of the test method. And it is fresh because the fixture is initialized prior to each method.
Transient Fresh Fixtures ensure that your tests are independent, can execute concurrently, and can execute in any order. They also ensure that you never need a tear-down method because nothing persists beyond the fixture — it's all destroyed at the end of the test. If you need a tear-down method, that's an indicator that there is something about the fixture that is not transient.
A Persistent Fresh Fixture is one that otherwise persists from test to test and needs to be torn down within each test method to make it fresh. Examples include fixtures that create resources such as files, sockets, semaphores, database connections, etc. The goal of the tear-down method is to delete or reset any persistent parts of the fixture — making them fresh again for the next test.
Users of NUnit or x-Unit should note that these frameworks do not create a fresh instance between test methods — which means that all tests written in those frameworks are persistent. This will require tear-down methods to freshen them up.
A Persistent Shared Fixture is one that allows some state (or resource) to persist from test to test. Since some resources can be very expensive to create and destroy within every test method (such as database connections), it is usually best to share that resource across a suite of tests. In JUnit, this can be accomplished using the @BeforeClass attribute to designate suite setups and the @AfterClass attribute to designate suite teardowns.
You do not need to choose between these three approaches. Within any given test suite, you could very well have tests that use Transient Fresh Fixtures, some that use Persistent Fresh Fixtures, and some that use Persistent Shared Fixtures. But it is usually best to keep your fixtures as fresh and as transient as possible — keeping tear-down to a minimum. This will facilitate independent and flexible tests.