ghu*_*sse 27 javascript unit-testing mocking reactjs jestjs
我使用create-app-component创建了一个项目,它使用构建脚本(babel,webpack,jest)配置新的应用程序.
我写了一个我正在尝试测试的React组件.该组件需要另一个javascript文件,公开一个函数.
我的search.js文件
export {
search,
}
function search(){
// does things
return Promise.resolve('foo')
}
Run Code Online (Sandbox Code Playgroud)
我的反应成分:
import React from 'react'
import { search } from './search.js'
import SearchResults from './SearchResults'
export default SearchContainer {
constructor(){
this.state = {
query: "hello world"
}
}
componentDidMount(){
search(this.state.query)
.then(result => { this.setState({ result, })})
}
render() {
return <SearchResults
result={this.state.result}
/>
}
}
Run Code Online (Sandbox Code Playgroud)
在我的单元测试中,我想检查是否search使用正确的参数调用了该方法.
我的测试看起来像这样:
import React from 'react';
import { shallow } from 'enzyme';
import should from 'should/as-function';
import SearchResults from './SearchResults';
let mockPromise;
jest.mock('./search.js', () => {
return { search: jest.fn(() => mockPromise)};
});
import SearchContainer from './SearchContainer';
describe('<SearchContainer />', () => {
it('should call the search module', () => {
const result = { foo: 'bar' }
mockPromise = Promise.resolve(result);
const wrapper = shallow(<SearchContainer />);
wrapper.instance().componentDidMount();
mockPromise.then(() => {
const searchResults = wrapper.find(SearchResults).first();
should(searchResults.prop('result')).equal(result);
})
})
});
Run Code Online (Sandbox Code Playgroud)
我已经很难弄清楚如何jest.mock工作,因为它需要变量作为前缀mock.
但是如果我想测试方法的参数search,我需要在我的测试中使模拟函数可用.
如果我转换模拟部分,使用变量:
const mockSearch = jest.fn(() => mockPromise)
jest.mock('./search.js', () => {
return { search: mockSearch};
});
Run Code Online (Sandbox Code Playgroud)
我收到此错误:
TypeError:(0,_search.search)不是函数
无论我试图访问jest.fn和测试参数,我都无法使它工作.
我究竟做错了什么?
Tom*_*mty 46
您收到该错误的原因与如何提升各种操作有关.
即使在您的原始代码中,您只需SearchContainer 在为mockSearchjest 指定值并调用jest 之后导入mock,但规范指出:Before instantiating a module, all of the modules it requested must be available.
因此,在SearchContainer导入时,依次导入search,您的mockSearch变量仍未定义.
人们可能会发现这很奇怪,因为它似乎也暗示着search.js没有被嘲笑,所以嘲笑根本不起作用.幸运的是,(babel-)jest确保提升调用mock和类似功能甚至高于导入,因此模拟将起作用.
尽管如此,mockSearch模拟函数引用的赋值将不会随着mock调用而提升.因此,相关操作的顺序将是这样的:
./search.jsmockSearch当第2步发生时,search传递给组件的函数将是未定义的,并且步骤3中的赋值为时已晚,无法更改.
如果您将模拟函数创建为mock调用的一部分(这样它也将被提升),它将在组件模块导入时具有有效值,如您的早期示例所示.
正如您所指出的,当您想在测试中使模拟函数可用时,问题就开始了.有一个明显的解决方案:单独导入您已经模拟过的模块.
既然你现在知道开玩笑实际上是在进口之前发生的,那么一个简单的方法就是:
import { search } from './search.js'; // This will actually be the mock
jest.mock('./search.js', () => {
return { search: jest.fn(() => mockPromise) };
});
[...]
beforeEach(() => {
search.mockClear();
});
it('should call the search module', () => {
[...]
expect(search.mock.calls.length).toBe(1);
expect(search.mock.calls[0]).toEqual(expectedArgs);
});
Run Code Online (Sandbox Code Playgroud)
实际上,您可能想要替换:
import { search } from './search.js';
Run Code Online (Sandbox Code Playgroud)
附:
const { search } = require.requireMock('./search.js');
Run Code Online (Sandbox Code Playgroud)
这应该不会产生任何功能差异,但可能使你正在做的事情更明确(并且应该帮助任何人使用类型检查系统,如Flow,所以它不认为你试图调用模拟函数在原件上search).
如果您需要模拟的是模块本身的默认导出,那么所有这些都是绝对必要的.否则(正如@publicJorn指出的那样),你可以简单地在测试中重新分配特定的相关成员,如下所示:
import * as search from './search.js';
beforeEach(() => {
search.search = jest.fn(() => mockPromise);
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
29628 次 |
| 最近记录: |