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