Java 中多个条件的单元测试?
Unit Test for multiple condition in Java?
我是单元测试的新手,有时我会遇到多种情况。但是,我不确定我是否为每个测试重新模拟或验证相同的案例。
例如,我正在尝试为以下服务方法编写单元测试:
public void create(Request request) {
// code omitted
if (!employeeService.existsByUuid(uuid)) {
throw new EntityNotFoundException("Not found");
}
EmployeeDTO employee = employeeService.save(...);
if (!departmentService.existsByUuid(employee.getDepartment())) {
throw new EntityNotFoundException("Not found");
}
}
我想我需要为以下场景编写测试:
1.当employeeService.existsByUuid(uuid) == false
时,则抛出新的EntityNotFoundException。然后验证 employeeService.save()
和 departmentService.existsByUuid()
从未被调用。
2. when employeeService.existsByUuid(uuid) == true
then employeeService.save()
is called and I assert the values.然后验证 employeeService.save()
和 departmentService.existsByUuid()
从未被调用。
3. 当 departmentService.existsByUuid() == false
然后抛出新的 EntityNotFoundException。在这个阶段,我还将 employeeService.existsByUuid(uuid)
模拟为 true
以便测试通过第一个条件。但是,我不确定是否需要断言第二部分; employeeService.save()
被调用,我断言这些值。我是断言返回值还是只验证该方法被调用了 1 次。因为我已经声明了它的值,而第三个测试只是针对第三个条件。
当我们有多个条件并且可能需要一次又一次地重新测试相同的条件时,对于这种情况有什么想法吗?
您不应尝试逐行测试您的代码,而应使用涵盖单个有意义场景的案例。因此,如果您已经有一个检查条件的用例,则不必在其他测试用例中重复这些断言。
在你的例子中,我认为这些可能是核心案例:
- 如果UUID不存在,则抛出异常,不保存员工
- 如果UUID存在,则所有员工字段都被正确保存
- 如果保存了员工,但员工所属部门不存在则抛出异常
要测试它们,您可以这样做:
EmployeeService employeeService = mock(EmployeeService.class);
案例 1:
when(employeeService.existsByUuid(employeeUuid)).thenReturn(false);
try {
testObject.create(request);
fail();
}
catch(EntityNotFoundException e) {
verify(employeeService, never()).save(...);
}
案例 2:
when(employeeService.existsByUuid(employeeUuid)).thenReturn(true);
when(employeeService.existsByUuid(departmentUuid)).thenReturn(true);
testObject.create(request);
verify(employeeService).save(field1, field2, ...);
案例 3:
when(employeeService.existsByUuid(employeeUuid)).thenReturn(true);
when(employeeService.existsByUuid(departmentUuid)).thenReturn(false);
try {
testObject.create(request);
fail();
}
catch(EntityNotFoundException e) {
// success
}
顺便说一句,您还可以在 @Test 注释中指明预期的异常,但是您无法对结果进行任何进一步检查:
@Test(expected = EntityNotFoundException.class)
public void test3() {
when(employeeService.existsByUuid(employeeUuid)).thenReturn(true);
when(employeeService.existsByUuid(departmentUuid)).thenReturn(false);
testObject.create(request);
}
您可以使用 mockito verify 和 assert throw 来测试您的目标,如下所示
@Test
public void testOne(){
when(employeeService.existsByUuid(uuid)).thenReturn(false);
assertThrows(EntityNotFoundException.class, () -> {
create(request);
});
verify(employeeService, times(0)).save(eq(empObj));
verify(departmentService, times(0)).existsByUuid(eq(departmentObj));
}
@Test
public void testTwo(){
when(employeeService.existsByUuid(uuid)).thenReturn(true);
when(departmentService.existsByUuid(uuid)).thenReturn(true);
create(request);
verify(employeeService, times(1)).save(eq(empObj));
verify(departmentService, times(1)).existsByUuid(eq(departmentObj));
}
@Test
public void testThree(){
when(employeeService.existsByUuid(uuid)).thenReturn(true);
when(departmentService.existsByUuid(uuid)).thenReturn(false);
assertThrows(EntityNotFoundException.class, () -> {
create(request);
});
verify(employeeService, times(1)).save(eq(empObj));
verify(departmentService, times(1)).existsByUuid(eq(departmentObj));
}
我是单元测试的新手,有时我会遇到多种情况。但是,我不确定我是否为每个测试重新模拟或验证相同的案例。
例如,我正在尝试为以下服务方法编写单元测试:
public void create(Request request) {
// code omitted
if (!employeeService.existsByUuid(uuid)) {
throw new EntityNotFoundException("Not found");
}
EmployeeDTO employee = employeeService.save(...);
if (!departmentService.existsByUuid(employee.getDepartment())) {
throw new EntityNotFoundException("Not found");
}
}
我想我需要为以下场景编写测试:
1.当employeeService.existsByUuid(uuid) == false
时,则抛出新的EntityNotFoundException。然后验证 employeeService.save()
和 departmentService.existsByUuid()
从未被调用。
2. when employeeService.existsByUuid(uuid) == true
then employeeService.save()
is called and I assert the values.然后验证 employeeService.save()
和 departmentService.existsByUuid()
从未被调用。
3. 当 departmentService.existsByUuid() == false
然后抛出新的 EntityNotFoundException。在这个阶段,我还将 employeeService.existsByUuid(uuid)
模拟为 true
以便测试通过第一个条件。但是,我不确定是否需要断言第二部分; employeeService.save()
被调用,我断言这些值。我是断言返回值还是只验证该方法被调用了 1 次。因为我已经声明了它的值,而第三个测试只是针对第三个条件。
当我们有多个条件并且可能需要一次又一次地重新测试相同的条件时,对于这种情况有什么想法吗?
您不应尝试逐行测试您的代码,而应使用涵盖单个有意义场景的案例。因此,如果您已经有一个检查条件的用例,则不必在其他测试用例中重复这些断言。
在你的例子中,我认为这些可能是核心案例:
- 如果UUID不存在,则抛出异常,不保存员工
- 如果UUID存在,则所有员工字段都被正确保存
- 如果保存了员工,但员工所属部门不存在则抛出异常
要测试它们,您可以这样做:
EmployeeService employeeService = mock(EmployeeService.class);
案例 1:
when(employeeService.existsByUuid(employeeUuid)).thenReturn(false);
try {
testObject.create(request);
fail();
}
catch(EntityNotFoundException e) {
verify(employeeService, never()).save(...);
}
案例 2:
when(employeeService.existsByUuid(employeeUuid)).thenReturn(true);
when(employeeService.existsByUuid(departmentUuid)).thenReturn(true);
testObject.create(request);
verify(employeeService).save(field1, field2, ...);
案例 3:
when(employeeService.existsByUuid(employeeUuid)).thenReturn(true);
when(employeeService.existsByUuid(departmentUuid)).thenReturn(false);
try {
testObject.create(request);
fail();
}
catch(EntityNotFoundException e) {
// success
}
顺便说一句,您还可以在 @Test 注释中指明预期的异常,但是您无法对结果进行任何进一步检查:
@Test(expected = EntityNotFoundException.class)
public void test3() {
when(employeeService.existsByUuid(employeeUuid)).thenReturn(true);
when(employeeService.existsByUuid(departmentUuid)).thenReturn(false);
testObject.create(request);
}
您可以使用 mockito verify 和 assert throw 来测试您的目标,如下所示
@Test
public void testOne(){
when(employeeService.existsByUuid(uuid)).thenReturn(false);
assertThrows(EntityNotFoundException.class, () -> {
create(request);
});
verify(employeeService, times(0)).save(eq(empObj));
verify(departmentService, times(0)).existsByUuid(eq(departmentObj));
}
@Test
public void testTwo(){
when(employeeService.existsByUuid(uuid)).thenReturn(true);
when(departmentService.existsByUuid(uuid)).thenReturn(true);
create(request);
verify(employeeService, times(1)).save(eq(empObj));
verify(departmentService, times(1)).existsByUuid(eq(departmentObj));
}
@Test
public void testThree(){
when(employeeService.existsByUuid(uuid)).thenReturn(true);
when(departmentService.existsByUuid(uuid)).thenReturn(false);
assertThrows(EntityNotFoundException.class, () -> {
create(request);
});
verify(employeeService, times(1)).save(eq(empObj));
verify(departmentService, times(1)).existsByUuid(eq(departmentObj));
}