如何模拟使用 Axios 进行的 API 调用?
How to mock API calls made with Axios?
我有一个名为 Home.jsx 的组件,它在 axios 实例的帮助下在 useEffect 中进行异步调用。现在在 Home.test.jsx 中为 Home 编写测试时,我遇到了这个 API 调用的问题,因为 API 调用需要授权并且测试是 运行 在终端而不是浏览器。如果我使用 findBy
或 waitFor
那么 API 调用应该会失败,因为没有授权发生。我正在使用 axios.create({})
实例,没有其他问题帮助我。
//Home.jsx
import services from "../../Services/patientServices";
const Home = () => {
const [patientSets, setPatientSets] = useState([]);
const fetchPatientSets = async () => {
try {
const result = await services.patientSets();
console.log('Data => ', result);
setPatientSets(result.data);
}
catch(err) {
setPatientFetching(false);
}
}
useEffect(() => {
fetchPatientSets();
}, []);
}
//Services.js
import apiClient from "./apiClient";
const patientSets = async () => {
return await apiClient().get(`patient_sets`);
};
//ApiClient.js
const apiClient = () => {
const access_token = localStorage.getItem("access_token");
const instance = axios.create({
baseURL: window.config.apiUrl,
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${access_token}`,
},
responseType: "json"
});
return instance;
}
//Home.test.jsx
import React from 'react';
import { render, screen } from '../../setupTests';
import Home from './Home';
describe('Home', () => {
test('Test refresh button in the table', async () => {
const { container } = render(<Home />);
expect(await screen.findBy('async data').toBeInTheDocument();
});
});
Home
组件直接依赖于patientServices
模块。为了使单位尽可能小,你应该模拟 patientServices
而不是 axios
.
单元越大,测试越复杂。
例如
Home.jsx
:
import services from './services/patientServices';
import React, { useState, useEffect } from 'react';
export const Home = () => {
const [patientSets, setPatientSets] = useState([]);
const fetchPatientSets = async () => {
try {
const result = await services.patientSets();
console.log('Data => ', result);
setPatientSets(result.data);
} catch (err) {}
};
useEffect(() => {
fetchPatientSets();
}, []);
return (
<div>
<ul>
{patientSets.map((p) => {
return <li key={p.id}>{p.name}</li>;
})}
</ul>
</div>
);
};
apiClient.js
import axios from 'axios';
const apiClient = () => {
const access_token = localStorage.getItem('access_token');
const instance = axios.create({
baseURL: window.config.apiUrl,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${access_token}`,
},
responseType: 'json',
});
return instance;
};
export default apiClient;
services/patientServices.js
:
import apiClient from '../apiClient';
const patientSets = async () => {
return await apiClient().get(`patient_sets`);
};
export default { patientSets };
Home.test.jsx
:
import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { Home } from './Home';
import services from './services/patientServices';
jest.mock('./services/patientServices');
describe('67122477', () => {
afterAll(() => {
jest.resetAllMocks();
});
it('should pass', async () => {
const mResult = { data: [{ name: 'teresa teng', id: '1' }] };
services.patientSets.mockResolvedValueOnce(mResult);
render(<Home />);
const matched = await screen.findByText(/teresa teng/);
expect(matched).toBeInTheDocument();
});
});
测试结果:
PASS examples/67122477/Home.test.jsx (11.771 s)
67122477
✓ should pass (45 ms)
console.log
Data => { data: [ { name: 'teresa teng', id: '1' } ] }
at examples/67122477/Home.jsx:10:15
---------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------------|---------|----------|---------|---------|-------------------
All files | 80.77 | 100 | 62.5 | 82.61 |
67122477 | 85.71 | 100 | 83.33 | 84.21 |
Home.jsx | 100 | 100 | 100 | 100 |
apiClient.js | 50 | 100 | 0 | 50 | 4-13
67122477/services | 60 | 100 | 0 | 75 |
patientServices.js | 60 | 100 | 0 | 75 | 4
---------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 14.449 s
我有一个名为 Home.jsx 的组件,它在 axios 实例的帮助下在 useEffect 中进行异步调用。现在在 Home.test.jsx 中为 Home 编写测试时,我遇到了这个 API 调用的问题,因为 API 调用需要授权并且测试是 运行 在终端而不是浏览器。如果我使用 findBy
或 waitFor
那么 API 调用应该会失败,因为没有授权发生。我正在使用 axios.create({})
实例,没有其他问题帮助我。
//Home.jsx
import services from "../../Services/patientServices";
const Home = () => {
const [patientSets, setPatientSets] = useState([]);
const fetchPatientSets = async () => {
try {
const result = await services.patientSets();
console.log('Data => ', result);
setPatientSets(result.data);
}
catch(err) {
setPatientFetching(false);
}
}
useEffect(() => {
fetchPatientSets();
}, []);
}
//Services.js
import apiClient from "./apiClient";
const patientSets = async () => {
return await apiClient().get(`patient_sets`);
};
//ApiClient.js
const apiClient = () => {
const access_token = localStorage.getItem("access_token");
const instance = axios.create({
baseURL: window.config.apiUrl,
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${access_token}`,
},
responseType: "json"
});
return instance;
}
//Home.test.jsx
import React from 'react';
import { render, screen } from '../../setupTests';
import Home from './Home';
describe('Home', () => {
test('Test refresh button in the table', async () => {
const { container } = render(<Home />);
expect(await screen.findBy('async data').toBeInTheDocument();
});
});
Home
组件直接依赖于patientServices
模块。为了使单位尽可能小,你应该模拟 patientServices
而不是 axios
.
单元越大,测试越复杂。
例如
Home.jsx
:
import services from './services/patientServices';
import React, { useState, useEffect } from 'react';
export const Home = () => {
const [patientSets, setPatientSets] = useState([]);
const fetchPatientSets = async () => {
try {
const result = await services.patientSets();
console.log('Data => ', result);
setPatientSets(result.data);
} catch (err) {}
};
useEffect(() => {
fetchPatientSets();
}, []);
return (
<div>
<ul>
{patientSets.map((p) => {
return <li key={p.id}>{p.name}</li>;
})}
</ul>
</div>
);
};
apiClient.js
import axios from 'axios';
const apiClient = () => {
const access_token = localStorage.getItem('access_token');
const instance = axios.create({
baseURL: window.config.apiUrl,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${access_token}`,
},
responseType: 'json',
});
return instance;
};
export default apiClient;
services/patientServices.js
:
import apiClient from '../apiClient';
const patientSets = async () => {
return await apiClient().get(`patient_sets`);
};
export default { patientSets };
Home.test.jsx
:
import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { Home } from './Home';
import services from './services/patientServices';
jest.mock('./services/patientServices');
describe('67122477', () => {
afterAll(() => {
jest.resetAllMocks();
});
it('should pass', async () => {
const mResult = { data: [{ name: 'teresa teng', id: '1' }] };
services.patientSets.mockResolvedValueOnce(mResult);
render(<Home />);
const matched = await screen.findByText(/teresa teng/);
expect(matched).toBeInTheDocument();
});
});
测试结果:
PASS examples/67122477/Home.test.jsx (11.771 s)
67122477
✓ should pass (45 ms)
console.log
Data => { data: [ { name: 'teresa teng', id: '1' } ] }
at examples/67122477/Home.jsx:10:15
---------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------------|---------|----------|---------|---------|-------------------
All files | 80.77 | 100 | 62.5 | 82.61 |
67122477 | 85.71 | 100 | 83.33 | 84.21 |
Home.jsx | 100 | 100 | 100 | 100 |
apiClient.js | 50 | 100 | 0 | 50 | 4-13
67122477/services | 60 | 100 | 0 | 75 |
patientServices.js | 60 | 100 | 0 | 75 | 4
---------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 14.449 s