Service层的单元测试:在测试方法单元性和所需Mock的次数上取得平衡

都说单元测试应该喵准单个方法,每个测试方法只测一小部分逻辑。

但另一方面,如果测试时总是要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. 虽然只测了最大方法,但小方法的各种逻辑依然可以覆盖全,只要你穷举四个叶结点的真值表组合即可

Leave a Comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.