Vue 单元测试中,对 watch 的思考。
引言
以下 watch 部分摘自 vue 官方文档
1 | watch: { |
第一个思路
如果要对这个模块进行测试,通常第一个想到的流程是
- 新建这个 Vue 实例
- 更改 question 的值,以触发这个回调函数
伪代码:
1 | let vue = new Vue({ |
在实际编写测试用例的过程中遇到了问题,对数据的更改操作,是在下一轮事件循环中才会被 watch 发现,换言之,如果在同一个事件循环中,数据发生了多次变化,被检测到的只有这一轮事件循环里面的最后一次变化。
而当测试框架没有做特别的处理,断言是不会像所预期的那样子工作,因为在 assertFunctionCall
的时候,watcherFunction
还没有被调用。
vue 官方提供了 $nextTick 函数,这个函数作用类似于 setTimeout,在下一轮事件循环的末尾加入一个任务,以下写法,断言是在 watch 函数调用之后执行的。
1 | let vue = new Vue({ |
这种写法的用例,如果没有使用 async/await 关键字,需要使用 Promise 或者 done 函数来让测试用例以异步函数的形式来运行(即下一个用例等待这个用例的断言结果)
另外一种思路
在 vue 的运行机制中,会根据构造函数中传入的 watch 对象建立一些 watcher 实例,
- watcher 可以用过 expression 字段找到,如对 question 字段进行监听,则 expression 字段值为 ‘question’
- watcher 有一个
run
方法,以下是去掉了注释的源码,在编写测试用例的时候,可以在改变数据以后,直接调用 watcher.run,然后断言回调函数有没有被正确调用。
1 | Watcher.prototype.run = function run () { |
测试用例类似这样,如此便屏蔽了事件循环,done 函数等概念。
1 | let vue = new Vue({ |