这周开始写 UI 的测试,发现了一些套路,让我感觉写测试更容易了。UI 测试无非就是找到对应的 element,然后基于这个 element 进行交互,之后验证结果,验证结果可以正向验证正确的结果,也可以反向验证错误的结果,还可以验证某个函数是否被调用了。
可以将 UI 分为几个层次,比如数据获取层,数据转换层,page,container,component,这样测试起来更有针对性。我们现在的代码划分的没这么细,只有 page 和 component 层,后面可以慢慢的重构。
理解了测试的原理就会让测试写起来更加容易,测试实际上就是要构建一个虚拟/测试环境,让当前的代码在这个环境中执行,以模拟真实环境下的操作。比如 react 项目要在浏览器的环境中运行,单元测试的时候不是真的要跑一个浏览器来运行,而是模拟一个浏览器,这里的模拟就是模拟浏览器的 js 执行引擎和 dom,因为要通过 js 引擎解析 js 代码,然后 render 成 dom 结构。模拟的这个测试环境还是有一定的工作量的,所以目前有些 api 不支持,需要组合不同的库来增加这些支持,让我们的模拟环境尽可能完整和真实。比如 jest 中使用 jsdom 来模拟 dom 环境,jsdom 对于密码学库的支持就不是很好,所以在测试这类的代码时会报错,这个错误不一定是你的代码真有错误,而是测试时 jsdom 不支持某些代码中的 api 导致的错误。这时候或者用别的库,或者自己写一个假的实现,我们叫 mock。
mock 让我们更加容易的测试有依赖和有副作用的代码,比如我的代码中在点击某个 button 后,会跳转到别的页面:history.push(another_page); 这个测试一是不太容易测试,因为我们不知道如何确定跳转后是否在下一个页面,就算知道了,比如通过 url 判断,那如果这个 url 变化就很容易导致我们的测试失败,这种依赖我们应该隔离掉,隔离的方法就是用 mock,我可以写一个假的实现,让 history.push 什么都不做,只记录被谁调用了,这样我就知道每次提交按钮后这个 history.push 确实执行了。
在使用 jest 进行测试的时候,经常会遇到一个错误,组件被 unmount 了,setState 会失败,要用 act 包装起来什么的。想了一下,这个错误是因为当我们做一些异步操作的时候,需要等待异步操作完成,而这个异步操作发生在组件之外,比如通过 api 获取某个数据,组件在测试的时候是不知道这个异步操作啥时候结束的,这时候就需要 wait 一下,可以显式的告诉组件如何去等,比如等待某个 element 出现,然后继续后面的测试。react testing library 提供了 waitFor 函数,可以方便的等待异步的执行。每次 userEvent.click 不需要 await,而 userEvent.type 就需要 await 了。
有了测试,我们的代码就更加具有稳定性,让我们更有信心,对于未来产品的变化也更从容。另外测试对于我们的代码质量也有提升,因为如果要写出可以测试的代码,那代码本身就不会有很大的耦合,因为耦合多了,就不容易测试了。
和练球类似,写测试的过程中,让我感觉到,开始做一件事情都是有点慢的,慢慢的熟悉了之后,自然速度就会加快,质量也会慢慢的提升,成就感也会更强。不过前提是要坚持下来,找到正确的方式,并用正确的方式持续的做下去。
网友评论