都说单元测试应该喵准单个方法,每个测试方法只测一小部分逻辑。
但另一方面,如果测试时总是要Mock,你就要想办法少Mock一些东西,因为Mock代码写起来是很累、很难看的
Service层的代码往往就是这种情况。看个例子:
你会怎么测下面这样的代码:
//仔细看下,这是一棵4层的判定树 public class Service { //为了层次清晰,没有使用驼峰式命名 public boolean do_biz() { if (!is_biz_one_valid()) { return false; } return is_biz_two_valid(); } boolean is_biz_two_valid() { if (!is_two_a_valid()) { return false; } return is_two_b_valid(); } boolean is_two_b_valid() { if (!is_two_b_left_valid()) { return false; } return is_two_b_right_valid(); } ...
本着每个测试方法只测一小块逻辑的原则,你可能会这样写:
@Test public void test_do_biz() { Service service = new Service(); // do mocking expect_biz_one_valid(service); expect_biz_two_valid(service); assertTrue(service.do_biz()); } @Test public void test_biz_two() { Service service = new Service(); // do mocking expect_biz_two_a_valid(service); expect_biz_two_b_valid(service); assertTrue(service.is_biz_two_valid()); } @Test public void test_biz_two_b_valid() { Service service = new Service(); // do mocking expect_two_b_left_valid(service); expect_two_b_right_valid(service); assertTrue(service.is_two_b_valid()); } ... //只写了正例
问题:
1. 你写了6个mock方法: expect_biz_one_valid,expect_biz_two_valid …Mock太多了,搞的测试类比被测类还长…..
2. 如果被测类是一棵判定树,那你差不多对每个中间层结点都写了测试; 但,真的需要对它们都进行测试吗? 别忘了,你只有一个public方法,你只想直接验证 y = f(one,two_a,two_b_left,two_b_right) 结果,并不愿意分别验证 two_b = f(two_b_left, two_b_right), two = f(two_a, two_b), y = f(one,two)
何不干脆这样写:
@Test public void test_do_biz() { Service service = new Service(); // do mocking expect_biz_one_valid(service); expect_biz_two_a_valid(service); expect_two_b_left_valid(service); expect_two_b_right_valid(service); assertTrue(service.do_biz()); } //只写了正例
结果是:
1. 这样你直接针对最大方法的进行测试,没那么“单元”,但仍达到了你的测试目的,因为你只想验证y=f(a,b,c,d)在a,b,c,d 在各种取值时的正确性
2. Mock了四个方法(即判定树的叶结点),比原来的6个少了一些
3. 虽然只测了最大方法,但小方法的各种逻辑依然可以覆盖全,只要你穷举四个叶结点的真值表组合即可