详解Jest结合Vue-test-utils使用的初步实践(7)
但是在执行之后我们发现并非如此,spy并未被调用,原因是:
watch中的方法被Vue**推迟**到了更新的下一个循环队列中去异步执行,如果这个watch被触发多次,只会被推送到队列一次。这种缓冲行为可以有效的去掉重复数据造成的不必要的性能开销。
所以当我们设置了inputValue为'ok'之后,watch中的方法并没有立刻执行,但是expect却执行了,所以断言失败了。
解决方法就是将断言放到$nextTick中,在下一个循环队列中执行,同时在expect后面执行Jest提供的done()方法,Jest会等到done()方法被执行才会结束测试。
it('is called with the new value in other cases', (done) = > { wrapper.vm.inputValue = 'ok'; wrapper.vm.$nextTick(() = > { expect(spy).toBeCalled(); done() }) });
在测试第二个情况时,由于对inputValue赋值时spy会被执行一次,所以需要清除spy的状态,这样才能得出正确的预期:
it('is not called with same value', (done) = > { wrapper.vm.inputValue = 'ok'; wrapper.vm.$nextTick(() = > { // 清除已发生的状态 spy.mockClear(); wrapper.vm.inputValue = 'ok'; wrapper.vm.$nextTick(() = > { expect(spy).not.toBeCalled(); done() }) }) });
测试方法
单元测试的核心之一就是测试方法的行为是否符合预期,在测试时要避免一切的依赖,将所有的依赖都mock掉。
创建Test3组件,输入问题后,点击按钮后,使用axios发送HTTP请求,获取答案
<template> <div class="wrapper"> <label for="input">问题:</label> <input id="input" type="text" v-model="inputValue"> <button @click="getAnswer">click</button> <p>答案:{{answer}}</p> <img :src="src"> </div> </template> <script> import axios from 'axios'; export default { name: 'Test3', data() { return { inputValue: 'ok?', answer: '', src: '' } }, methods: { getAnswer() { const URL = 'https://yesno.wtf/api'; return axios.get(URL).then(result => { if (result && result.data) { this.answer = result.data.answer; this.src = result.data.image; return result } }).catch(e => {}) } } } </script> <style scoped> .wrapper { width: 500px; margin: 0 auto; text-align: left; } </style>
这个例子里面,我们仅仅关注测试getAnswer方法,其他的忽略掉。为了测试这个方法,我们需要做的有:
- 我们不需要实际调用axios.get方法,需要将它mock掉
- 我们需要测试是否调用了axios方法(但是并不实际触发)并且返回了一个Promise对象