使用模拟公理适配器模拟放置请求



我有一个简单的 Vue 组件,它在创建时获取 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)返回空的放置数组:

{ 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: [] }

我试图在描述块和控制台中定义 mockAxios.log迭代后它 - 事实证明 put 请求在这里。但不是在我需要的时候。:)

我做错了什么?也许有一些方法可以检查是否调用了创建的回调并且其中的所有异步函数都已完成?也许我用错了公理模拟?

此测试代码应通过:

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. 只对端点进行了一次GET调用(使用expect(......get.length).toBe(1)),那么你真的应该使用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()实用程序为每个挂载创建一个 Vue 的本地实例,以避免污染全局 Vue 实例(如果您有多个测试组,则很有用)

最后,7.最好将此测试分解为多个it语句;单元测试应该是微观测试,即测试一个小的,清晰可识别的行为。虽然我没有为您分解测试,因此它包含尽可能少的更改,但我强烈建议这样做。

最新更新