模拟使用模拟-axios-适配器发出请求

时间:2019-03-31 08:51:03

标签: vue.js mocking axios axios-mock-adapter

我有一个简单的Vue组件,该组件会在创建API密钥时获取API密钥,并且可以通过单击按钮来更新密钥:

<template>
    <div>
        <div>{{data.api_key}}</div>
        <button ref="refresh-trigger" @click="refreshKey()">refresh</button>
    </div>
</template>
<script>
    export default {
        created() {
            axios.get(this.url).then((response) => {
                this.data = response.data
            })
        }
        methods: {
            refreshKey() {
                axios.put(this.url).then((response) => {
                    this.data = response.data
                })
            },
        }
    }
</script>

我想用以下代码对其进行测试:

import {shallowMount} from '@vue/test-utils';
import axios from 'axios';
import apiPage from '../apiPage';
import MockAdapter from 'axios-mock-adapter';



describe('API page', () => {
    it('should renew API key it on refresh', async (done) => {
        const flushPromises = () => new Promise(resolve => setTimeout(resolve))
        const initialData = {
            api_key: 'initial_API_key',
        };
        const newData = {
            api_key: 'new_API_key',
        };
        const mockAxios = new MockAdapter(axios);

        mockAxios.onGet('/someurl.json').replyOnce(200, initialData)
        mockAxios.onPut('/someurl.json').replyOnce(200, newData);

        const wrapper = shallowMount(api);
        expect(wrapper.vm.$data.data.api_key).toBeFalsy();

        await flushPromises()

        wrapper.vm.$nextTick(() => {
            expect(wrapper.vm.$data.data.api_key).toEqual(initialData.api_key);
            done()
        });

        wrapper.find({ref: 'refresh-trigger'}).trigger('click');

        wrapper.vm.$nextTick(() => {
            console.log(mockAxios.history)

            expect(wrapper.vm.$data.data.api_key).toEqual(newData.api_key);

            expect(mockAxios.history.get.length).toBe(1);
            expect(mockAxios.history.get[1].data).toBe(JSON.stringify(initialData));

            expect(mockAxios.history.put.length).toBe(1);
            done();
        });
    })
});

但是事实证明,只有get请求被嘲笑了,因为我收到了:

        [Vue warn]: Error in nextTick: "Error: expect(received).toEqual(expected)

Difference:

    - Expected
    + Received

    - new_API_key
    + initial_API_key"

found in

---> <Anonymous>
<Root>

console.error node_modules/vue/dist/vue.runtime.common.dev.js:1883
{ Error: expect(received).toEqual(expected)

更糟糕的是,console.log(mockAxios.history)返回空的put数组:

{ get:
   [ { transformRequest: [Object],
       transformResponse: [Object],
       timeout: 0,
       xsrfCookieName: 'XSRF-TOKEN',
       xsrfHeaderName: 'X-XSRF-TOKEN',
       maxContentLength: -1,
       validateStatus: [Function: validateStatus],
       headers: [Object],
       method: 'get',
       url: '/admin/options/api.json',
       data: undefined } ],
  post: [],
  head: [],
  delete: [],
  patch: [],
  put: [],
  options: [],
  list: [] }

我试图在describe块中定义mockAxios,并在迭代后用console.log进行记录-事实证明放置请求在此处。但不是在我需要的时候。 :)

我在做什么错?也许有一些方法可以检查是否调用了创建的回调,并且其中的所有异步函数都已完成?也许我使用axios-mock错误?

1 个答案:

答案 0 :(得分:0)

此测试代码应通过:

import {shallowMount, createLocalVue} from '@vue/test-utils';
import axios from 'axios';
import api from '@/components/api.vue';
import MockAdapter from 'axios-mock-adapter';
describe('API page', () => {
    it('should renew API key it on refresh', async () => {
        const flushPromises = () => new Promise(resolve => setTimeout(resolve))
        const initialData = {
            api_key: 'initial_API_key',
        };
        const newData = {
            api_key: 'new_API_key',
        };
        const mockAxios = new MockAdapter(axios);
        const localVue = createLocalVue();
        mockAxios
          .onGet('/someurl.json').reply(200, initialData)
          .onPut('/someurl.json').reply(200, newData);

        const wrapper = shallowMount(api, {
          localVue,
        });
        expect(wrapper.vm.$data.data.api_key).toBeFalsy();

        await flushPromises();
        expect(wrapper.vm.$data.data.api_key).toEqual(initialData.api_key);
        wrapper.find({ref: 'refresh-trigger'}).trigger('click');
        await flushPromises();
        console.log(mockAxios.history);
        expect(wrapper.vm.$data.data.api_key).toEqual(newData.api_key);

        expect(mockAxios.history.get.length).toBe(1);
        expect(mockAxios.history.put.length).toBe(1);

    })
});

一些注意事项:

  1. 我更喜欢将响应链式链接到mockAxios对象上,这样您就可以按URL对其进行分组,这样就可以清楚您在嘲笑哪个端点:
mockAxios
  .onGet('/someurl.json').reply(200, initialData)
  .onPut('/someurl.json').reply(200, newData);

mockAxios
  .onGet('/anotherUrl.json').reply(200, initialData)
  .onPut('/anotherUrl.json').reply(200, newData);
  1. 如果要测试仅对端点(使用expect(......get.length).toBe(1)进行了一次GET调用,则应真正使用reply()而不是replyOnce()并对其进行测试您已经在做的方式。 replyOnce()函数将在第一次回复后删除处理程序,随后的请求中将得到404。

  2. mockAxios.history.get[1].data将不包含任何内容,原因有3个:GET请求没有正文(仅URL参数),您仅发出1个GET请求(此处您正在检查第二个GET),以及此语句是指已发送的请求,而不是您收到的数据。

  3. 您正在使用async/await功能,这意味着您可以利用$ nextTick的功能:await wrapper.vm.$nextTick();并放下done()调用,但是由于您已经拥有flushPromises(),您也可以使用它。

  4. 您无需使用以下代码来测试您在第一个调用中是否收到initialData: expect(mockAxios.history.get[1].data).toBe(JSON.stringify(initialData));,因为您已经使用expect(...).toEqual(apiKey)对其进行了测试。

  5. 使用createLocalVue()实用程序为每个avoid contaminating全局Vue实例的安装创建Vue的本地实例(如果您有多个测试组,则很有用)

最后,是7.最好将此测试分解为多个it语句;单元测试应该是 micro 测试,即测试小的,可明确识别的行为。尽管我没有为您分解测试,所以它包含的更改尽可能少,但我还是强烈建议您这样做。