Search code examples
javaunit-testingtestingjunitspring-test

Global mock objects for tests?


I am creating Spring Boot Web application, and I am using JUnit 5 for unit tests.

I have one concern about unit testing. Is good practice to make some mock objects global in one class, and after just return them with function when we need them in different tests classes?

I am asking this because I recently added one new field in my model class, and needed to modify bunch of test classes and add this field to constructor in every test class.

Lets for example take three classes Semester, Module and Course, where Course have Semester and Module as a fields:

@AllArgsConstructor
public class Module{
  private Long id;
  private String name;
}


@AllArgsConstructor
public class Semester{
  private Long id;
  private LocalDate startingDate;
}

@AllArgsConstructor
public class Course {
  private Long id;
  private String name;
  private Module module;
  private Semester semester;
}

Now, in all test classes where we need some kind of Course object we will need to create all of them, like this:

private final Module mockModule = Module(1L, "Computer Sciences");
private final Semester mockSemester = Semester(1L, LocalDate.of(2021, Month.MARCH, 1));
private final Course mockCourse = Course(1L, "DSA", mockModule, mockSemester); 

And after some time we discovered that we need one more field in module class, for example codeName:

@AllArgsConstructor
public class Module{
  private Long id;
  private String name;
  private String codeName;
}

After this one field change, we will need to edit all of the test classes where we are using Module constructor. The same will be if we want to add new field in Semester class.

But in the situation where we have all mock objects in one class, we will need to edit only constructor in this one class, not in all test classes. And the code in test class will be:

private final Course mockCourse = mockObjects.getMockCourse();

Is there a "cleaner" way of doing this?

I tried to find answer to this, but in all tutorials/articles about unit testing I found that every test class have their own mock objects.


Solution

  • You can apply the Object Mother pattern here and create a global factory class to construct objects for multiple tests to reduce boilerplate code. In case your object structure changes, you'll only have to touch a single file (at best).

    Tom Hombergs wrote a great article where he showcased the Object Mother in combination with the builder pattern.

    In the end, you'll have something like the following:

    CourseMother.completedCourse();
    CourseMother.emptyCourse();
    // etc.