实现比任何其他类型的测试更多的集成测试

单元测试在后端服务中使用起来很棒,但是在前端则有些棘,因为前端UI细节经常发生变化而不改变更大的用户流程,这会导致很多单元测试失败。需要花很多时间去更新单元测试。

集成测试验证大功能甚至整个页面,但没有任何后端、真实数据或真实浏览器。六日渲染登录页面,输入用户名和密码,点击”登录“按钮并验证是否发送了正确的网络请求,但实际上并没有进行任何网络请求。

单元测试集成测试的差异

单元测试集成测试
一个测试仅涵盖一个模块一个测试涵盖整个功能或页面
重构后经常需要重写大多数情况下经受得住重构
难以避免测试实现细节更好地模拟用户使用应用程序

奖杯模型

image.png

从底层开始:

  • Static analysis - 静态分析,捕捉语法错误、不良实践和错误使用的API
  • Unit tests - 单元测试工具 验证复杂算法是否正确工作
  • Integration tests - 集成测试工具 让您确信引用程序的所有功能都能按照预期工作
  • End-to-end tests - 端到端测试 - 确保应用作为一个整体运行:前后端、数据库和其他所有内容

避免测试内部问题

test('shows a success message after submission', () => { const wrapper = mount(<SubscriptionForm />); wrapper.instance().handleEmailChange('[email protected]'); wrapper.instance().handleSubmit(); expect(wrapper.state('isSubmitted')).toBe(true);});

上面测试存在的问题:

  • 如果您更改处理状态的方式(例如,将 React 状态替换为 Redux 或钩子),甚至重命名状态字段或方法,此测试将失败;
  • 它不测试表单是否实际从用户的角度正常工作:表单可能未连接到 handleSubmit 方法,当 isSubmitted 为真时,成功消息可能不会出现;

TIP

  1. 第一个问题称为假负:即使行为保持不变,测试也会失败。这样的测试使重构变得非常困难,您永远不知道测试失败是因为您破坏了某些内容还是因为测试不好。
  2. 第二个问题被称为假阳性:即使代码出错,测试也会通过。这样的测试并不能让你确信代码实际上对用户有用。

测试应该是确定性的

有些测试可能有时候通过有时候不通过,这种测试用例叫做 非确定性测试,造成这一问题的因素可能包括

  • 时区问题
  • 不同的文件系统
  • 在每次测试之前不清除和重新填充数据库
  • 多个测试用例之间存在共享的状态
  • 等等…

良好的测试是确定性的,它们不依赖于环境

避免不必要的期望和测试

expect(pizza).toBedefinde();
expect(pizza).toHaveAProperty('cheese', 'Mozarella');

如果第一个 pizza 没有定义,那么第二个用例无论如何都是会失败的,所以第一个测试用例是没有必要实现的

不要追求100%的测试覆盖率

一味的追求测试覆盖率存在一些问题

  • 高测试覆盖率会让你产生一种虚假的安全感。“覆盖的代码”意味着代码在测试运行期间被执行,但这并不意味着测试实际上在验证这段代码的功能。即使测试覆盖率不到 100%,你可以确定你没有测试某些代码,但即使覆盖率达到 100%,你也不能确定你测试了所有内容。
  • 有些功能真的很难测试,比如浏览器中的文件上传或拖放。你开始模拟或访问组件内部,因此你的测试不再像用户使用应用程序的方式,而且难以维护。最终,你开始花更多时间编写不太有用的测试,这就是所谓的收益递减问题。

100% 的测试覆盖率在两种情况下是有用的:库和开源项目中

来源: