文章系列
[质量提升之道]-Code Review

前言

上一篇介绍了 Code Review,本篇将介绍 UT&Coverage,两者都是代码入库前做的质量工作,从流程上细分,UT&Coverage 在 Code Review 之前。从 Coding 开始,Bug 就开始蠢蠢欲动了,UT&Coverage 的最大价值,就是把缺陷扼杀在摇篮之中,此时的修复成本是最低的,修复风险也是最小的,做的好能很大程度的提高版本质量。

UT&Coverage 的概念

什么是 UT?
单元测试是最小颗粒度的测试,测试对象往往是某个方法、SQL,相对于静态分析,它是种基于白盒的动态测试。

为什么要 UT&Coverage?
单元测试要和代码覆盖率配合使用,UT 的目的就是要测试代码覆盖到业务代码中的方法、方法内的分支路径,执行者需要知道 UT 的执行情况,比如覆盖率是多少,是否达到预期。

UT&Coverage 的工具组合

每种语言都有各自的工具,如果用 Java,常见的组合是 Junit/JaCoCo。
工具的安装不是本文重点,想了解的自行谷歌度娘。

UT 的策略和测试代码

单元测试不是无的放矢,应该是有目标、有策略的进行:
1.制定目标:class 覆盖率达到多少、method 覆盖率达到多少、line 覆盖率达到多少;
2.制定策略:如果开发进度紧迫,可以优先保证重要的、核心的部分被覆盖到,例如:Controller、Service 的代码、底层公共方法等;
3.测试代码的设计,要尽量覆盖方法内的各条分支路径。

spring boot 的示例

/**
 * Controller业务代码
 */
@RestController
@RequestMapping("/gretting")
@Api("swagger生成的gretting api文档")
@Slf4j
public class Controller {
    @ApiOperation(value = "索引", notes = "index目录")
    @GetMapping(value = "/index")
    public ResponseEntity<?> index() {
        log.info("GreetingController.index.in.");
        log.error("kidding");
        Map<String, Object> map = new HashMap<>();
        map.put("msg", "Hello, SpringBoot");
        return ResponseEntity.ok(map);
    }
}

/**
 * Controller测试代码
 */
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class TestController {
    @Autowired
    MockMvc mvc;

    @Before
    public void setUp() {
    }

    @Test
    public void index() throws Exception {
        mvc.perform(MockMvcRequestBuilders
                .get("/gretting/index"))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.content().string("{\"msg\":\"Hello, SpringBoot\"}"));
    }

    @After
    public void tearDown() {
    }
}
/**
 * Service业务代码
 */
@Service
public class ServiceImpl implements Service {

    @Override
    public String getStr(Object obj) {
        return null == obj ? "false" : "true";
    }
}

/**
 * Service测试代码 - 未覆盖分支路径.
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestService {
    private String expect;

    @Autowired
    private ServiceImpl service;

    @Before
    public void setUp() {
        expect = "success";
    }

    @Test
    public void getStr() throws Exception {
        String str = service.getStr("test");
        Assert.assertEquals(expect, str);
    }

    @After
    public void tearDown() {

    }
}
/**
 * Service测试代码 - 覆盖分支路径.
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestService {
    private String expect;

    @Autowired
    private ServiceImpl service;

    @Before
    public void setUp() {
        expect = "success";
    }

    @Test
    public void getStr() throws Exception {
        String str = service.getStr("test");
        Assert.assertEquals(expect, str);
        //  测试覆盖分支路径
        str = service.getStr(null);
        Assert.assertNull(str);
    }

    @After
    public void tearDown() {

    }
}
/**
 * UT入口
 */
@Suite.SuiteClasses({TestService.class, TestController.class})
@RunWith(Suite.class)
public class TestMain {
}

JaCoCo 的 Coverage

1.代码覆盖率可以作为版本提测的硬性指标,例如:method 覆盖率 100%,line 覆盖率不低于 80%;
2.JaCoCo 可以设置统计样本的目标范围,可以是包(com.demo.controller.、com.paic.demo.service.),也可以是某个类(com.paic.demo.service.ClassDemo);
3.UT&Coverage 作为版本的提测指标,在持续集成中执行,建议在本地 IDE 先跑一遍,提高版本提测的通过率。

覆盖率报告

绿色的代表已覆盖到的代码,红色代表未覆盖到的代码

后话

UT&Coverage、Code Review 属于白盒测试的范畴,需要人工介入,是整个团队打赢质量攻坚战最重要的战役,研发和测试都要高度重视。以本人多年的工作经验,如果该环节不做或做的不好就进行提测,对黑盒测试的测试人员,肯定是个灾难,靠时间和人力去堆砌,也不见得有好的结果。

下一次,会介绍测试左移和提测标准。


↙↙↙阅读原文可查看相关链接,并与作者交流