单元测试的最佳实践

整体架构

合适的架构可以提升可测试性。比如菱形对称架构的模块化和解耦特性使得系统各个部分可以独立进行单元测试。这不仅提高了测试的效率,还能够减少测试的依赖性,提高测试准确性。

代码设计

代码设计和可测试性有密切关联。强烈建议一个方法的代码行数不要太多。这样,如果需要细粒度单元测试(需要比较高的代码覆盖率的单元测试),就更容易。大不了把私有方法变成公有,加一

@VisibleForTesting注解来测试。

其他设计比如采用易于测试的设计模式:‌选择合适的设计模式可以显著提高代码的可测试性。‌例如,‌使用依赖注入(‌DI)‌模式可以使依赖关系在运行时动态绑定,‌便于模拟和替换依赖项,‌从而更容易进行单元测试。‌

测试框架

分布式微服务系统而言,"粗粒度单元测试"最大挑战在于如何解决周边依赖问题,对于一个典型的应用而言,它可能会依赖数据库、消息中间件、缓存系统等,以及周边的其它服务。如何处理这些依赖,是我们必须要面对和要解决的问题。

其实解决方案只有一种叫Test Double(测试替身),即要用"替身"来代替依赖,从而让程序在没有真正依赖环境的情况下,仍然可以运行,验证功能。这些"替身"有不少fancy的名字,比如dummy、fake、stub、mock、spy等,这里我就不啰嗦这些概念的差异了,也不重要。重要的是我们该如何高效的实施"粗粒度单元测试"。

Mock做替身

使用mock做"替身"是我们处理外部依赖的最常见做法,有很多的框架比如Mockito,EasyMock支持我们去做mock的事情。

这种方法有效,但存在两个问题:

比较繁琐,当需要构造的对象有大量字段的时候,需要额外写很多的代码。

有些功能测不全,比如这里的SQL语句就不能被测试到,因为数据库的访问是被mock掉的。

Embedded Server做替身

鉴于以上的问题,我发现很多团队都开始转向embedded方案,即在本地拉起一个真实的内嵌依赖服务,作为依赖的"替身"。比如我用到了Redis缓存,那么我可以使用embedded-redis启动一个本地的redis,从而连接到"真实"的redis环境。使用很简单,只需要加入下面的依赖就可以。在Junit5的Extension帮助下,我们可以很优雅的使用embedded的服务。

xml 复制代码
<dependency>
  <groupId>com.github.codemonstur</groupId>
  <artifactId>embedded-redis</artifactId>
  <version>1.4.2</version>
  <scope>test</scope>
</dependency>

类似的,我们常用的中间件比如kafka、MySQL、MongoDB等等都有相对应的embedded的方案。对于非中间件,比如其它服务依赖,我们可以使用wiremock来做其它服务API的"替身"。这些动作在很大程度上可以帮助我们消解依赖问题,这样做可以给我们带来以下好处:

在同样代码覆盖率的情况下,使用embedded的集成测试方案,可以写更少的测试用例和代码,研发效率更高

因为使用的是真实中间件服务,可以让我们的测试更加贴近真实环境,测试的有效性更高。

测试的入口是接口。这种更大测试粒度带来的好处是,可以帮助我们更好的重构内部业务逻辑,而不用担心破坏测试用例,如果UT太细的话,重构代码的同时还要重写UT,比较麻烦。

你也许会说,和Mock方案相比,这里的数据准备并没有比Mock少多少啊,实际上的确如此,对于测试数据,我们可以使用测试夹具(Test Fixtures)把测试数据用json/xml的形式放在resource下面,这样可以提升我们的数据复用和数据准备效率。

除此之外,embedded方案还引入了一个比较严重的问题------慢!即在运行测试的时候,需要拉起整个环境,整个过程很耗时,一般情况下,如果要启动3个embedded服务,短则一分钟多则几分钟,这显然与我们所期望的单测要"短平快"不相符。"慢"会极大的抑制我们运行UT的积极性,也就不能享受UT带来的quick feedback好处,更不用说TDD了。

相关推荐
王解3 小时前
Jest项目实战(4):将工具库顺利迁移到GitHub的完整指南
单元测试·github
Devil枫14 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试
小袁在上班20 小时前
Python 单元测试中的 Mocking 与 Stubbing:提高测试效率的关键技术
python·单元测试·log4j
测试199821 小时前
外包干了2年,快要废了。。。
自动化测试·软件测试·python·面试·职场和发展·单元测试·压力测试
安冬的码畜日常1 天前
【The Art of Unit Testing 3_自学笔记06】3.4 + 3.5 单元测试核心技能之:函数式注入与模块化注入的解决方案简介
笔记·学习·单元测试·jest
王解1 天前
Jest项目实战(2): 项目开发与测试
前端·javascript·react.js·arcgis·typescript·单元测试
程序员小雷2 天前
软件测试基础:单元测试与集成测试
python·功能测试·selenium·测试工具·单元测试·集成测试·压力测试
王解2 天前
Jest进阶知识:深入测试 React Hooks-确保自定义逻辑的可靠性
前端·javascript·react.js·typescript·单元测试·前端框架
程序员雷叔2 天前
外包功能测试就干了4周,技术退步太明显了。。。。。
功能测试·测试工具·面试·职场和发展·单元测试·测试用例·postman
安冬的码畜日常2 天前
【玩转 Postman 接口测试与开发2_005】第六章:Postman 测试脚本的创建(上)
javascript·测试工具·单元测试·postman·bdd·chai