Stubbing getter 而不仅仅是设置值

Stubbing getters instead of just setting values

我运行进入这样的单元测试

@InjectMocks
private PersonService personService;

@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Person person;

@Before
void init() {
    when(person.getFirstName()).thenReturn("John");
    when(person.getLastName()).thenReturn("Doe");
    when(person.getBirthDate()).thenReturn("1990-01-01"); //sorry about the date string, just an example
}

@Test
void shouldReturnCorrectAge() {
    Integer age = personService.getPersonAge(person);
    assertEquals(32, age);
}

为什么要存根?如果像下面的下一个代码那样直接赋值,有什么不同吗?一个比另一个更好吗?

Person person;

@Before
void init() {
    person = new Person();
    person.setFirstName("John");
    person.setLastName("Doe");
    person.setBirthDate("1990-01-01"); //sorry about the date string, just an example
}

@Test
void shouldReturnCorrectAge() {
    Integer age = personService.getPersonAge(person);
    assertEquals(32, age);
}

在第一个场景中,您正在模拟该方法。这样,如果 personService.getPersonAge() 调用任何这些 person 方法,它将 return 选定的值

在第二种情况下,您正在创建一个 Person 对象。在这种情况下,当您传递 person 参数时,您知道 return.

会发生什么

但是,如果您进行的不是 getter 数据库操作呢?在那种情况下,您不应该在测试中访问数据库,因此您将服务中的数据库方法模拟为 return 您想要的值。

我认为在这个例子中第二个选项更好。

像这样为简单的 getter 设置存根并不是真正需要的 - 对于存在外部 dependency/class 调用的情况,您通常应该保留模拟,而不是在包含简单值的 POJO 上。模拟有助于验证交互和跟踪方法被调用的次数(例如,如果您想要绝对确保在单元测试中满足某些条件时已调用某些 NotificationService 方法)。

在某些情况下,您可以像第二个示例一样轻松地在外部服务 class 中设置值,但是在测试单个 class 的功能时您仍应使用模拟 - mocks 帮助你设置测试的方式说 GIVEN 一些外部 service/method returns X,做 Y。验证其他 class' 输出的责任取决于那个 class'自己的单元测试。