写在前面
对于我们开发人员来说,单元测试一定不会陌生,但在各种原因下会被忽视,尤其是在我接触到的项目中,提测阶段发现各种各样的问题,我觉得有必要聊一下单元测试。
为了写而写的单元测试没什么价值,但一个好的单元测试带来的收益是非常客观的。问题是怎么去写好单元测试?怎么去驱动写好单元测试?
一 我们的现状
现状一:多个项目完全没有单元测试。
现状二:开发人员没有写单元测试的习惯,或者由于赶业务记录而没有时间去写。
现状三:单元测试写成了集成测试,比如容器、数据库,导致单元测试运行时间长,失去了意义。
现状四:太依赖集成测试。
以上是我在aone找的两个项目的测试情况,基本不考虑单元测试就合并发布,形同虚设。
站在开发的角度讲,导致以上问题的原因大概有以下几点:
1、开发成本
对于系统初期,可能要花很多时间去写新业务,对于老系统又太过庞大,无法下手。
2、维护成本
每修改相关的类,或者重构一次代码,我们就要去修改相应的单元测试。
3、ROI
投入产出是不是正收益?可能无论是管理者还是我们开发自己都回质疑这个问题,所以有时候没有强有力的动力。
二 怎么解决
说来说去都是成本的问题,所以我们怎么去解决成本呢?
那么,我们一切从最开始说起:开发的成本
一个单元测试的传统写法,包含以下几个方面:
- 测试数据 (被测数据,和依赖对象)
- 测试方法
- 返回值断言
@Test
public void testAddGroup() {
// 数据
BuyerGroupDTO groupDTO = new BuyerGroupDTO();
groupDTO.setGmtCreate(new Date());
groupDTO.setGmtModified(new Date());
groupDTO.setName("中国");
groupDTO.setCustomerId(customerId);
// 方法
Result<Long> result = customerBuyerDomainService.addBuyerGroup(groupDTO);
// 返回值断言
Assert.assertTrue(result.isSuccess());
Assert.assertNotNull(result.getData());
}
一个简单的测试还好,但如果是一逻辑复杂,且入参数据复杂的时候,那写起来其实挺头痛的。怎么解放我们程序员的双手?
“工欲善其事必先利其器”
我们以最大的努力降低我们的开发成本,这就涉及到我们测试框架和工具的选择问题
1 测试框架选择
首先第一个问题就是junit4和junit5的选择,【从junit4到junit5】 我觉得最便利的一个好处就是可以参数化测试,并且基于参数化测试我们可以更加灵活的配置我们的参数。
效果如下:
@ParameterizedTest
@ValueSource(strings = { "racecar", "radar", "able was I ere I saw elba" })
void palindromes(String candidate) {
assertTrue(StringUtils.isPalindrome(candidate));
}
更好的是,junit5提供了扩展,比如我们常用的json格式。这里我们使用json文件作为输入:
@ParameterizedTest
@JsonFileSource(resources = {"/com/cq/common/KMPAlgorithm/test.json"})
public void test2Test(JSONObject arg) {
Animal animal = JSONObject.parseObject(arg.getString("Animal"),Animal.class);
List<String> stringList = JSONObject.parseArray(arg.getString("List<String>&#