javascript - 如何在 React 组件中模拟服务以开玩笑地隔离单元测试?
问题描述
我正在尝试重构一个单元测试,以将使用 axios 调用 API 的服务与调用该服务的组件隔离开来。
该服务目前非常简单:
import axios from 'axios'
export default class SomeService {
getObjects() {
return axios.get('/api/objects/').then(response => response.data);
}
}
下面是调用该服务的组件片段:
const someService = new SomeService();
class ObjectList extends Component {
state = {
data: [],
}
componentDidMount() {
someService.getObjects().then((result) => {
this.setState({
data: result,
});
});
}
render() {
// render table rows with object data
}
}
export default ObjectList
我可以通过模拟 axios 来测试 ObjectList 是否按预期呈现数据:
// ...
jest.mock('axios')
const object_data = {
data: require('./test_json/object_list_response.json'),
};
describe('ObjectList', () => {
test('generates table rows from object api data', async () => {
axios.get.mockImplementationOnce(() => Promise.resolve(object_data));
const { getAllByRole } = render(
<MemoryRouter>
<table><tbody><ObjectList /></tbody></table>
</MemoryRouter>
);
await wait();
// test table contents
});
});
一切顺利通过。作为一项主要的学术练习,我试图弄清楚如何模拟 SomeService 而不是 axios,这就是事情出错的地方,因为我认为我对传递的内部结构了解不够。
例如,我认为由于 SomeService 只是返回 axios 响应,我可以类似地模拟 SomeService,有点像这样:
// ...
const someService = new SomeService();
jest.mock('./SomeService')
const object_data = {
data: require('./test_json/object_list_response.json'),
};
describe('ObjectList', () => {
test('generates table rows from object api data', async () => {
someService.getObjects.mockImplementationOnce(() => Promise.resolve(object_data))
// etc.
这失败并出现错误:Error: Uncaught [TypeError: Cannot read property 'then' of undefined]
,并且错误从以下位置追溯到此行ObjectList
:
someService.getObjects().then((result) => {
我具体需要模拟ObjectList
什么,以便组件可以获取SomeService
设置状态所需的内容?
解决方案
在使用 jest 文档中建议的不同方法进行了一些试验和错误之后,似乎唯一可行的方法是jest.mock()
使用模块工厂参数调用,如下所示:
// rename data to start with 'mock' so that the factory can use it
const mock_data = {
data: require('./test_json/object_list_response.json'),
};
jest.mock('./SomeService', () => {
return jest.fn().mockImplementation(() => {
return {
getObjects: () => {
return Promise.resolve(mock_data).then(response => response.data)
}
};
});
});
// write tests
使用mockResolvedValue()
不起作用,因为我无法.then()
摆脱它。
如果这会导致任何人找到更优雅或惯用的解决方案,我会欢迎其他答案。
推荐阅读
- angular - 为什么我在 Angular 7 中导入“Common”模块仍然无法使用 DatePipe?
- c# - 使用互操作删除 Word 中两次出现之间的文本
- python - 烧瓶重定向不起作用,但我没有收到任何错误
- python - 如何在 Tensorflow 数据集的地图转换中访问外部范围?
- python - 如果从不同的视图函数调用,则不会传递上下文数据
- html - 使用 XPath 从表中获取元素
- elasticsearch - Elasticsearch Nest DeleteMany 无法推断类型
- swift - 动态更新 tableview 单元格内的 CollectionView
- jsf - 单击拒绝时取消选中所有其他复选框,如果选中其他复选框则取消选中拒绝
- javascript - 如何处理非常长的数组