单元测试之道
一、前言
很多开发不写单测,可能是没有意识到单测的重要性,或者懒得写,这里单测的重要性就不多说了。还有一些同学写单测,但是基本上等于没写,比如像下面这种单测代码:
@Test public void testSave() { ItemClassesForm form = new ItemClassesForm(); Result result = itemClassesController.save(form); } |
问题比代码行数多得多。具体有什么问题这里先不挑明,等大家看完下面的要求应该就明白了。
二、原则
有一本书叫《单元测试之道》,推荐大家都去看一遍,这里列举的几个原则,书中都有提到和详细描述。
1、单元测试应该是自动化的
这一项含有的要求很多很多,我觉得最基本的一点就是测试结果的成功与否不需要人肉来判断。如果你还在观察用System.out.println来打印出的结果来判断是否成功,那估计这个用例也就是第一次有点用。如果有大量的测试用例要跑,靠人肉观察输出是不可能的。最简单的就是使用Assert,Junit和TestNG都有提供。
2、单元测试必须充分全面
单元测试其实是白盒测试,开发知道自己的代码逻辑,所以要尽可能地测试多个逻辑分支或者执行路径。举几个例子
- 查询接口如果支持批量查询,最好测一下传入单个参数或者多个参数这两个场景
- 查询接口如果有缓存,最好测一下缓存不命中和缓存命中两个情况
- 查询接口如果支持多个查询条件,最好把每个条件都覆盖一下
- 更新接口如果有幂等逻辑,需要重复调用测试一下幂等是否生效
这些都是基础的要求,还有一些场景要求比较严格,需要覆盖异常情况,比如对外的OpenAPI,需要测试不同条件下返回的错误码是否符合预期。
3、单元测试用例应该是可重复执行的
在不修改代码的情况下,单测用例每次跑的结果必须是一样的。一般来说这个对单测的数据提出了要求,不能使用固定的测试数据,比如某个创建接口要求资源名称不能重复,那么测试这个创建接口的代码如果使用固定的名称,那么只能是第一次跑会成功,后面都会失败。一个简单的办法是使用生成的数据,保证每次不重复。
4、单元测试应该是独立的
这一条其实包含了下面2个要求:
- 测试用例之间不能互相影响
- 测试数据不能污染测试环境正常的数据
有些比较大的公司,可能会使用独立的单元测试库,来保证不影响测试环境。当然也可以采取其他方法来做到这一点
5、单元测试应该是稳定的
为了尽量不受环境影响,如果用例所测试的逻辑需要依赖外部接口,可以通过mock机制来mock掉这些接口,返回预期的数据。
关于单元测试方面需要注意的事项还有很多,但是看到示例中的单元测试,我觉得还是先做到上面提到的这几点吧