Fixtures

Learn how to inject data into and perform activities before and after your tests.

What is a fixture?

Merriam-Webster’s dictionary defines a fixture as “a device for supporting work during machining.” This definition is pretty close to what we mean when we talk about fixtures in software testing. We can think of test fixtures as boundary conditions or preconditions that have to be verified for a test to begin. Many people think a test fixture is all the system setup you need for tests to run. That’s exactly what preconditions are—something that must be true at the beginning of a flow.

Classic fixture examples include database connections, sockets, and files. But they can also be simple objects or values that we use in our tests. If a test is based on an external value, that means the value must already be there, initialized as expected, for the test to run. We’ve been using fixtures in our code samples so far without even realizing it. Remember the EducativeSpec class? Let’s take a look at an extract.

package mdipirro.educative.io.effectiveunitandintegrationtestinginscala.matchers

import mdipirro.educative.io.effectiveunitandintegrationtestinginscala.TestSuite
import mdipirro.educative.io.effectiveunitandintegrationtestinginscala.model.v2.{Author, Educative, FreeCourse, Lesson}

class EducativeSpec extends TestSuite:

  private val educative = Educative(Seq(
    FreeCourse("Scala for Beginners", Author("John", "Doe"), Set.empty[Lesson], Set.empty[String]),
    FreeCourse("Scala for Data Analysis", Author("Mary", "Jane"), Set.empty[Lesson], Set("Scala")),
    FreeCourse("Functional Kotlin", Author("Mary", "Jane"), Set.empty[Lesson], Set("kotlin"))
  ))

  "The Educative platform" `should` "filter the courses by tag" in {
    val scalaCoursesTags = educative.filterByTag("Scala") map (_.tags)

    all(scalaCoursesTags) should contain ("Scala")
  }
First example of a data fixture

In this example, educative (line 8) is a fixture. The test case shown above won’t run if educative isn’t initialized properly. However, scalaCoursesTags (line 15) isn’t a fixture. It’s simply a temporary value we introduced in the body of our test to enhance code readability.

When a fixture is needed by more than one test, it’s good practice to avoid code duplication. In EducativeSpec we could have duplicated the educative initialization in every test case. This is a very bad practice, however, because the more code duplication we have in our tests and application code, the more difficult it will be to maintain that code.

Usually, we take great care to avoid duplication in applicative code. But tests are another story. Normally, developers couldn’t care less about tests, even though they’re as important as the applicative code. Spaghetti tests will lead to a drop in productivity because refactoring or extending applicative code often means refactoring or extending your tests.

In this lesson, we’ll take a look at several ways to define well-designed fixtures in our tests. Each ...