详解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对象
