如何写好 Android 单元测试

本贴最后更新于 2799 天前,其中的信息可能已经事过景迁

原文:WRITE AWESOME UNIT TESTS
作者:molsjeroen

unittests.png

如果你会写代码,那么你就会写单元测试。然而写好单元测试就是另一个话题了。你以为单元测试代码是需要你长期维护、重构和开发的产品级代码?别傻了!

本文旨在提供 3 个十分简单的规则来帮你玩儿转单元测试。每个规则之后都会给你提供可轻易实现的实用技巧。

1.要跑的足够快

写测试的目的就是为了运行他们。主要有两个好处:

  1. 确保程序正常执行
  2. 程序异常是查找原因

总体而言,测试是程序的安全保障,是避免回归测试的主要武器。它们使得你可以重构代码而不会引入已经修复的 bug。

然而,需要注意的是:你需要执行它们以使它们正常工作。

每次执行测试,它都会给你一个代码状况的反馈。反馈所用的时间越短,你找到问题的速度就越快,问题也就被修复的越快。也就是说你希望每做一次改动就执行一次测试,而不是在每次发布版本之前或基于每日的基础版本执行测试。

测试执行的越频繁,你从中得到的信息就越多。

你等待测试执行的时间越短,你经常执行它们的意愿就越高。简而言之,如果想要频繁的执行测试,那么测试代码执行的速度就必须要快,快到无可复加!

整个测试执行通过的时间应该限制在 1 秒之内,而不是 10 秒,更不能是 1 分钟。

这意味着你:

  • 要在 Java 虚拟机(JVM)上执行测试,而不能是在设备上
  • 要只测试独立的业务逻辑单元
  • 不要将 UI、数据库和网络测试包含在你的主测试套件中
  • 不要在测试中使用 wait/sleep 语句

2. 编写小而专的测试

要始终记得编写测试是为了找出问题。也就是说你需要明确设计测试用例的目的是为了捕获应用中的 bug。

假如应用中有一个 bug,你更喜欢哪种测试结果:

一个 bug -> 多条测试失败
一个 bug -> 只有一条测试失败

当然是第二个!因为这样比较容易调试。当一个测试失败时,你可以根据测试名称来查看哪里出了问题。

@Test
public void logInShouldFailWithWrongPassword() throws Exception {
  // Test code
}

每一个 bug 必须只有一个对应的测试失败。失败的原因需要用测试名来描述。

这样会强制你针对每个测试只检查一个点,并且会保持测试足够小而更容易理解,解释和维护。

这也是为什么一个好的测试应该像我们代码库中的其他方法一样,小(只有几行代码)而专(只测一个点)。

要做到这一点,你需要:

  • 在每条测试只包含一条断言/验证语句
  • 将少量的大测试拆解为大量的小测试
  • 在测试名中明确描述失败的原因

3. 100% 的可靠性

测试是程序的安全保障,所以你需要认真对待失败的测试。你需要放下手头所有的事情去解决问题。

想象一下,程序在你急切的想要添加一个新特性时突然出现了问题,而你不得不放下当前工作去修复出现的问题。这是多么令人沮丧的事情啊!!!

再想一下,如果你花费了几个小时的时间去分析问题,没有任何头绪,(绝望中)又执行了一次测试,所有的测试都通过了...

对开发者而言,最沮丧的事情莫过于浪费时间在那些清理一下工程或重启一下 IDE 就被修复的随机错误上。

如果多个测试都是这样的原因导致的,你会对整个测试套件失去信任。你不再认真对待失败的测试,也将不再从整个测试套件中得到任何帮助。

这也是为什么你要保持测试 100% 的可靠性,并且只在真正出现问题时使测试失败。

要做到这一点,你需要:

  • 在 JVM 上运行测试(与设备的连接可能会断开)
  • 在测试中模拟网络交互
  • 将 UI/集成测试移出单元测试套件

总结

测试执行的越频繁,你从中得到的信息就越多。好的单元测试依赖于足够快、专,并且可靠性足够高。

  • 测试
    53 引用 • 198 回帖
  • 翻译
    58 引用 • 84 回帖 • 1 关注
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    334 引用 • 323 回帖 • 2 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...