Lets say a university offers courses and courses are attended by students:
class University{
List<Course> courses;
}
class Course{
Category category;
List<Student> students;
}
class Student{
Gender getGender();
boolean hasGender(Gender gender);
}
I also have a class Filter
which should return all male students which attend courses in Category.MATH
public class Filter{
University university;
List<Student> selectSubgroup(){
//to be implemented
}
}
I normally use the builder pattern to write tests in such cases and i like it because of the readability.
class FilterTest{
@Test
void testThatOnlyMaleStudentsInCategoryMathAreSelected(){
when(university.getCourses()).thenReturn(
aCourse()
.with(Category.MATH)
.with(
aStudent()
.withGender(Gender.MALE),
aStudent()
.withGender(Gender.FEMALE)
)
);
assertThat(filter.selectSubgroup()).hasSize(1);
}
}
However, using this approach implies using the real method hasGender
of class Student
, so the test is not isolated.
Using mockito, a test might look like this:
class FilterTest{
@Test
void testThatOnlyMaleStudentsInCategoryMathAreSelected(){
when(university.getCourses()).thenReturn(Arrays.asList(course));
when(course.getStudents()).thenReturn(Arrays.asList(student, student2));
when(course.getCategory()).thenReturn(Category.MATH);
when(student.hasGender(eq(Gender.MALE))).thenReturn(true);
when(student.hasGender(eq(Gender.FEMALE))).thenReturn(false);
when(student2.hasGender(eq(Gender.FEMALE))).thenReturn(true);
when(student2.hasGender(eq(Gender.MALE))).thenReturn(false);
assertThat(filter.selectSubgroup()).hasSize(1);
}
}
I find this less readable, but all the dependendent classes are mocked. So, which approach is better?