写点什么

如何写好单元测试

作者:TroyLiu
  • 2022 年 3 月 15 日
  • 本文字数:1342 字

    阅读完需:约 4 分钟

如何写好单元测试

1. 测试应该是什么样?


一个好的测试应该是简单到一目了然,简单到根本不需要话时间去证明测试代码的正确性。

测试应该相互独立,之间不应该有依赖关系。测试执行的顺序不影响测试结果。

测试命名最好能明确表达出当前测试的含义:

  • test_save_item

  • test_throw_nullpointexception_while_name_null_value

2. 为什么觉得测试不好写?

测试不好写的主要原因:耦合。


编写可测试的代码,一个原则:编写组合的代码。

  • 不要在组件内部创建对象;

  • 尽量减少 static 方法的使用;

  • 将第三方代码进行隔离;

  • 框架回调的代码只编写简单的逻辑。

编写可测试的代码

简述:在组件内部创建对象,对 mock 不友好。static 方法的使用对测试不友好。框架回调代码,比如 spring controller 不应该写很多逻辑,逻辑应该写在 service 层,controller 应该只做简单的参数校验,然后将逻辑转发到 service 层。单元测试可以重点针对 service 层。第三方框架代码不隔离,有以下几个问题:

  • mock 不方便

  • 如果引入测试覆盖率工具,三方代码如有隔离层(封装层),可以将其排除在外,以实现 100% 测试覆盖率。否则无法实现 100% 测试覆盖率。

  • 重构时,如需要更换三方组件,修改繁琐,代码改动多。

​3. 怎样编写单元测试?

单元测试最好能和代码一起编写。一个需求可能比较大,如果整个需求都完成后再写单元测试,有以下几个问题:

  • 一个需求跨度可能长达几天时间,后补单元测试需要花时间回忆需求的详细情况,会产生遗漏的场景;

  • 写单元测试时,可能会发现代码结构问题导致测试不好写,如果需求都完成,调整结构的代价就比较大;

要实现单元测试与代码一起写,有一个点非常重要,那就是要做好任务分解。首先必须把任务分解到足够小,最好能分解到半个小时就能完成的一个小任务。这样编写完一个小任务后,立刻针对这个任务编写单元测试,这时的代码,代码编译没问题,单元测试全部通过,就可以将代码提交到 git。

单元测试最佳实践原则

4. 在现有系统上写测试

在一个现有系统上写测试,应该对代码进行重构,重构的关键是解耦。

现有系统上写测试的一个原则:动到哪里,改哪里。不需要为了写测试而去动代码,只需要跟随业务需求,需求需要动哪一部分代码,就改造这部分代码。

抛开复杂的与业务有关的结构重构,通用的重构包含一下几个要点:

  • 去掉 @Autowired 注入方式,更改为构造方法注入,便于后续 mock。如果不想手动添加构造方法,可以利用 lombok 的 @AllArgsConstructor 注解。

  • service 层尽量都提供一个接口,类应该只依赖接口,不要依赖具体实现。

  • 隔离(封装)第三方代码:比如 Spring 中的 KafkaTemplate、es 中的 RestClient、fastjson 中的 JSONObject 等。业务系统应该只依赖自己的封装层,不应该直接使用第三方代码。

5. FAQ

1.单元测试的应该细到什么力度?

答:单元测试应该对方法进行测试,由于推荐针对接口测试,故最小单位:公有方法。

2.如何减少单元测试带来的额外工作量?

答:

  1. 设计时就考虑单元测试的编写,避免后面写单元测试时发现由于耦合而无法写测试。

  2. 先画流程图,将整个业务考虑清楚后再动手写代码。

  3. 做好任务分解,大任务分解为小任务,边写业务代码边写单元测试。

  4. 多考虑设计模式,遵循 SOLID 原则:单一职责原则 、开放-关闭原则、里氏替换原则、依赖倒转原则、接口隔离原则、迪米特法则。

  5. 单元测试、集成测试代码,也是代码,做好测试代码的设计,重视测试代码的质量。

发布于: 刚刚阅读数: 2
用户头像

TroyLiu

关注

Just Do It. 2015.09.01 加入

2012 年工作,一直从事 Java 开发。对多线程与设计模式有自己的理解。热爱技术、喜欢的语言:Java、Golang、Perl。对 VIM 比较偏爱。使用 Dvorak 键盘。

评论

发布
暂无评论
如何写好单元测试_Java_TroyLiu_InfoQ写作平台