问题
For testing I use jest and react-test-renderer. It should be simple to test, however I have a hard time finding the proper example. I have tried to do something like that (in general I keep the functions in separate files):
utils.js
export const childFunction = () => 'something';
const parentFunction = () => childFunction();
export default parentFunction;
utils.test.js
import parentFunction from './utils.js';
it('childFunction should be called', () => {
const childFunction = jest.fn();
parentFunction();
expect(childFunction).toBeCalled();
})
The fragment const childFunction = jest.fn(); definitely won't work. While calling, parentFunction's body cares only about its own scope. But it also won't work if I import childFunction and do jest.mock(childFunction), because jest.mock needs a string, a url to a module, and not the function itself.
The example above doesn't work and I'm searching for an alternative. However this works after rendering the component with ShallowRenderer. And I'd like to achieve a similar behaviour with a function nested inside another function.
class Component extends React.Component {
componentDidMount() {parentFunction()}
render() {...}
}
const renderer = new ShallowRenderer();
describe("testing parentFunction", () => {
renderer.render(<Component/>);
it("parentFunction should be called", () => {
expect(parentFunction).toBeCalled();
});
});
回答1:
There's no way to spy on function call if a function isn't called as object method.
As explained in this answer, due to how ES modules work, it's possible to spy or mock a function only if it was exported from a module and is used in another module. This way it can be spied on module *
object, or be mocked with jest.mock
.
If this isn't the case, it should be tested indirectly:
expect(childFunction()).toBe('something');
expect(parentFunction()).toBe('something');
回答2:
not sure if this will help but it may give you ideas.
first, the example above:
// this needs to be stubbed
// const childFunction = () => 'something';
const childFunction = jest.fn();
const parentFunction = () => childFunction();
it('childFunction should be called', () => {
parentFunction();
expect(childFunction).toHaveBeenCalled();
}
this is a somewhat contrived example as it's unlikely that childFunction
is exported so you cannot get a reference to it and mock/stub it.
one workaround you have would be to move it out into its own method
class Component extends React.Component {
componentDidMount() {
this.parentFunction();
}
parentFunction() {
parentFunction(); // from elsewhere
}
render() {...}
}
This allows you to create a puncture and spy on the Component proto.
eg
const spy = jest.spyOn(Component.prototype, 'parentFunction');
// ... mount so lifecycle runs...
expect(spy).toHaveBeenCalled(); // and clear the spy mocks after!
it may be better to mock the module
eg you have utils.js used by your component that does:
export function parentFunction(){ console.log('parent'); }
component.js does:
import { parentFunction } from './utils';
you could in your tests do:
const utils = require('./utils');
utils.parentFunction = jest.fn();
import Component from './component';
// later
expect(utils.parentFunction).toHaveBeenCalled();
as you can see, many possible ways to go, though I am not sure on the value of that test, you should probably test the output / functionality of the component rather than it had called, having something run on componentDidMount
is a given and would only break if somebody converted to functional or changed the lifecycle name.
来源:https://stackoverflow.com/questions/52650367/jestjs-how-to-test-function-being-called-inside-another-function