GhostCat 的答案很简单、很好,并且专注于本质。
我将详细介绍其他一些需要考虑的问题,尤其是重构问题。
单元测试侧重于 API
类 API(公共函数)必须经过单元测试。
如果这 3 个功能是公开的,则每个功能都必须进行测试。
此外,单元测试不关注实现,而是关注预期行为。
今天,复合函数添加单个函数结果,明天它可以减去它们或其他任何结果。
测试C() 复合函数并不意味着再次测试A() 和B() 的所有场景,它意味着测试C() 的预期行为。
在某些情况下,对与单个函数集成的复合函数进行单元测试不会产生很多关于单个函数的重复。
在其他情况下,确实如此。我将在下一点介绍它。
测试C() 复合函数可能会导致测试中出现重复问题的示例。
假设A() 函数接受两个整数:
function A(int a, int b){ ...}
它对输入参数有以下限制:
- 它们必须 >=0
- 他们已经低于 100
- 他们的总和小于100
如果其中一项没有得到遵守,则会引发异常。
在A() 单元测试中,我们将测试这些场景中的每一个。每一个都可能在一个不同的测试用例中:
@Test
void A_throws_exception_when_one_of_params_is_not_superior_or_equal_to_0(){
...
}
@Test(expected = InvalidParamException.class);
void A_throws_exception_when_one_of_params_is_not_inferior_to_100(){
...
}
@Test(expected = InvalidParamException.class);
void A_throws_exception_when_params_sum_is_not_inferior_to_100(){
...
}
除了错误情况,我们还可以根据传递的参数为A() 函数提供多个标称场景。
假设B() 函数也有多个标称和错误场景。
那么聚合它们的C() 的单元测试呢?
您当然不应该重新测试这些案例中的每一个。它有很多重复,而且通过交叉两个函数的情况会有更多的组合。
下一点介绍如何防止重复。
可能的重构以改进设计并减少复合功能单元测试中的重复
在编写复合函数时,首先要考虑的是复合函数是否不应位于特定组件中。
composite component -> unitary component(s)
将它们解耦可以改善整体设计并赋予组件更具体的职责。
此外,它还提供了一种自然的方法来减少复合组件的单元测试中的重复。
实际上,如果需要,您可以存根/模拟单一组件行为,而无需为它们创建详细的固定装置。
复合组件单元测试可以专注于复合组件的行为。
因此,在我们之前的示例中,我们可以对C() 函数进行单元测试,而不是测试A() 和B() 的所有情况,而是可以存根或模拟A() 和B() 以便它们的行为正如C() 场景所预期的那样。
例如对于带有与A() 和B() 相关的错误案例的C() 测试场景,我们不需要重复每个A() 或B() 场景案例:
@Test(expected = InvalidParamException.class);
void C_throws_exception_when_a_param_is_invalid(){
when(A(any,any)).thenThrow(new InvalidParamException());
C();
}
@Test(expected = InvalidParamException.class);
void C_throws_exception_when_b_param_is_invalid(){
when(B(any,any)).thenThrow(new InvalidParamException());
C();
}