Java中多个条件的单元测试?

发布于 2025-01-14 15:11:02 字数 1316 浏览 1 评论 0原文

我是单元测试的新手,有时会遇到具有多种条件的情况。但是,我不确定是否为每个测试重新模拟或验证相同的情况。

例如,我正在尝试为以下服务方法编写单元测试:

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.employeeService.existsByUuid(uuid) == true 时,调用 employeeService.save() 并断言这些值。然后验证 employeeService.save()departmentService.existsByUuid() 从未被调用。

3.departmentService.existsByUuid() == false时抛出新的EntityNotFoundException。在此阶段,我还将 employeeService.existsByUuid(uuid) 模拟为 true,以便测试通过第一个条件。但是,我不确定是否需要断言第二部分;调用 employeeService.save() 并断言这些值。我是否断言返回值或仅验证该方法被调用 1 次。因为我已经断言了它的值,而第三个测试只是针对第三个条件。

当我们有多种条件并且可能需要一次又一次地重新测试相同的条件时,对于这种情况有什么想法吗?

I am new in Unit Testing and I have sometimes such situations with multiple conditions. However, I am not sure if I re-mock or verify the same cases for each test.

For example, I am trying to write Unit Tests for the following service method:

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");
    }
}

I think I need to write my tests for the following scenarios:

1. when employeeService.existsByUuid(uuid) == false, then throw new EntityNotFoundException. then verify employeeService.save() and departmentService.existsByUuid() is never called.

2. when employeeService.existsByUuid(uuid) == true then employeeService.save() is called and I assert the values. and then verify employeeService.save() and departmentService.existsByUuid() is never called.

3. when departmentService.existsByUuid() == false then throw new EntityNotFoundException. At this stage, I also mock employeeService.existsByUuid(uuid) as true so that test passes the first condition. However, I am not sure if do I need to assert the second part; employeeService.save() is called and I assert the values. Do I assert of the returned values or just verify that method is called 1 time. Because I already asserted its value and the 3rd test is just for the 3rd condition.

Any idea for this kind of scenarios when we have multiple condition and may need to re-test the same condition again and again?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

睫毛溺水了 2025-01-21 15:11:02

您不应该尝试逐行测试代码,而应该使用涵盖单个有意义场景的案例。因此,如果您已经有一个检查条件的案例,则不必在其他测试案例中重复这些断言。

在您的示例中,我认为这些可能是核心情况:

  1. 如果 UUID 不存在,则会引发异常,并且
  2. 如果 UUID 存在,则不会保存员工,
  3. 如果保存了员工,则所有员工字段都将正确保存,但员工的部门不存在,抛出异常

要测试它们,您可以执行以下操作:

EmployeeService employeeService = mock(EmployeeService.class);

case 1:

when(employeeService.existsByUuid(employeeUuid)).thenReturn(false);   
try {
    testObject.create(request);
    fail();
}
catch(EntityNotFoundException e) {
    verify(employeeService, never()).save(...);
}

case 2:

when(employeeService.existsByUuid(employeeUuid)).thenReturn(true); 
when(employeeService.existsByUuid(departmentUuid)).thenReturn(true);    
testObject.create(request);
verify(employeeService).save(field1, field2, ...);

case 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);
}

You should not try to test your code line by line, but with cases that cover a single meaningful scenario. So if you already have a case which checks a condition, you don't have to repeat those asserts in other test cases.

In your example I think these could be the core cases:

  1. if the UUID does not exist, an exception is thrown and the employee is not saved
  2. if the UUID exists, all the employee fields are saved correctly
  3. if the employee is saved, but the employee's department does not exist an exception is thrown

To test them you could do something like this:

EmployeeService employeeService = mock(EmployeeService.class);

case 1:

when(employeeService.existsByUuid(employeeUuid)).thenReturn(false);   
try {
    testObject.create(request);
    fail();
}
catch(EntityNotFoundException e) {
    verify(employeeService, never()).save(...);
}

case 2:

when(employeeService.existsByUuid(employeeUuid)).thenReturn(true); 
when(employeeService.existsByUuid(departmentUuid)).thenReturn(true);    
testObject.create(request);
verify(employeeService).save(field1, field2, ...);

case 3:

when(employeeService.existsByUuid(employeeUuid)).thenReturn(true);   
when(employeeService.existsByUuid(departmentUuid)).thenReturn(false);   
try {
    testObject.create(request);
    fail();
}
catch(EntityNotFoundException e) {
    // success
}

BTW you can also indicate expected exceptions in the @Test annotation, but then you cannot do any further checking on the results:

@Test(expected = EntityNotFoundException.class)
public void test3() {
    when(employeeService.existsByUuid(employeeUuid)).thenReturn(true);   
    when(employeeService.existsByUuid(departmentUuid)).thenReturn(false);   
    testObject.create(request);
}
友谊不毕业 2025-01-21 15:11:02

您可以使用mockito verify和assert throws来测试您的目标,如下所示

    @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));
    }

You can use mockito verify and assert throws to test your objectives something like below

    @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));
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文