Jestjs как проверить функцию, вызываемую внутри другой функции

Для тестирования я использую jest и react-test-renderer. Это должно быть просто проверить, однако мне сложно найти подходящий пример. Я пробовал сделать что-то подобное (вообще я храню функции в отдельных файлах):

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();
})

Фрагмент const childFunction = jest.fn (); определенно не будет работать. При вызове тело parentFunction заботится только о своей собственной области видимости. Но это также не сработает, если я импортирую childFunction и выполняю jest.mock (childFunction), потому что jest.mock нужна строка, URL-адрес модуля, а не сама функция.

Приведенный выше пример не работает, и я ищу альтернативу. Однако это работает после рендеринга компонента с помощью ShallowRenderer. И я хотел бы добиться аналогичного поведения с функцией, вложенной в другую функцию.

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();
  });
});

person Dune    schedule 04.10.2018    source источник


Ответы (2)


Невозможно шпионить за вызовом функции, если функция не вызывается как метод объекта.

Как объясняется в этом ответе, из-за того, как работают модули ES, можно шпионить или имитировать функцию только в том случае, если она была экспортирована. из модуля и используется в другом модуле. Таким образом, за ним можно шпионить за объектом модуля * или высмеивать с помощью jest.mock.

Если это не так, его следует протестировать косвенно:

expect(childFunction()).toBe('something');
expect(parentFunction()).toBe('something');
person Estus Flask    schedule 04.10.2018
comment
Ага, кажется, я могу забыть, наблюдая, была ли вызвана функция где-то, кроме компонента. Ценно знать, что я хотел сделать невозможное. :) - person Dune; 05.10.2018

не уверен, что это поможет, но это может дать вам идеи.

сначала пример выше:

// this needs to be stubbed
// const childFunction = () => 'something';
const childFunction = jest.fn();

const parentFunction = () => childFunction();

it('childFunction should be called', () => {
    parentFunction();
    expect(childFunction).toHaveBeenCalled();
}

это несколько надуманный пример, поскольку маловероятно, что childFunction экспортируется, поэтому вы не можете получить ссылку на него и имитировать / заглушить его.

один обходной путь, который у вас есть, - переместить его в свой собственный метод

class Component extends React.Component {
  componentDidMount() {
    this.parentFunction();
  }
  parentFunction() {
    parentFunction(); // from elsewhere
  }
  render() {...}
}

Это позволяет создавать прокол и следить за прототипом компонента.

eg

const spy = jest.spyOn(Component.prototype, 'parentFunction');

// ... mount so lifecycle runs... 
expect(spy).toHaveBeenCalled(); // and clear the spy mocks after!

может быть лучше поиздеваться над модулем

например, у вас есть utils.js, используемый вашим компонентом, который:

export function parentFunction(){ console.log('parent'); }

component.js делает:

import { parentFunction } from './utils';

вы могли бы сделать в своих тестах:

const utils = require('./utils');
utils.parentFunction = jest.fn();
import Component from './component';
// later
expect(utils.parentFunction).toHaveBeenCalled();

как вы можете видеть, существует множество возможных вариантов, хотя я не уверен в ценности этого теста, вам, вероятно, следует протестировать вывод / функциональность компонента, а не он вызвал, наличие чего-то, работающего на componentDidMount, является заданным и будет ломается только в том случае, если кто-то преобразовал его в функциональный или изменил имя жизненного цикла.

person Dimitar Christoff    schedule 04.10.2018
comment
Спасибо за ответ. Однако проверка того, была ли вызвана функция parentFunction, здесь не проблема, а проверка того, была ли вызвана функция childFunction внутри parentFunction. И я экспортирую свою дочернюю функцию просто для теста. Я отредактирую свой вопрос, чтобы показать, как выглядит моя файловая структура. - person Dune; 05.10.2018