#jestjs
#jestjs
Вопрос:
У меня есть файл, экспортирующий две функции a
и b
, где b
выполняется вызов a
.
Я хотел бы издевательски a
проверить, что при моем вызове b
он вызывает a
с некоторыми параметрами, но поскольку две функции находятся в одном файле, я не могу найти никакого способа сделать это.
functions.js
export const a = (x) => { a very complicated function };
export const b = (x) => a(x 1);
functions.test.js
import { a, b } from './functions';
describe('b', () => {
test('calling b calls a with x 1', () => {
const fakeA = //mock function a ... don't know how to.
b(1);
expect(fakeA).toHaveBeenCalledWith(2);
});
});
Комментарии:
1. Ты не можешь этого сделать. Либо разделите их на разные модули, либо протестируйте как единое целое.
2.
a
является деталью реализацииb
. В тестах вы даже не знаете, что он существует. Или, если задокументированное поведениеb
зависит отa
, тоa
должно быть предоставлено в качестве аргументаb
(и вы можете предоставить макет в тестах).3. Чтобы переформулировать мой предыдущий комментарий: предполагая, что я должен использовать функцию
b
, нужно ли мне что-либо знать оa
(для использованияb
)?a
Есть ли какие-то побочные эффекты, о которых я должен заботиться при использованииb
? Если ответ «нет», тоa
это деталь реализацииb
, и тест, который вы написали в вопросе, следует удалить. Это не вариант использования, это не помогает вам разрабатыватьb
; это мешает вам изменятьb
реализацию.4. @axiac, ну, в моем реальном случае
a
должен вызываться с множеством параметров, которые я не хочу издеваться, и у него также есть множество побочных эффектов, таких как отправка sms и электронных писем. Поэтому мне действительно нужно протестировать этиb
вызовыa
с ожидаемыми параметрами, не вызывая фактическиеa
.5. Похоже,
a
делает слишком много вещей. Я предполагаю, чтоb
это сложнее, чем описано в вопросе, но, тем не менее, тот факт, что он вызываетa
, является просто деталью реализации, а не ее результатом. Его результатом является электронная почта, SMS и, возможно, другие. Вариант использования должен ожидать вызова функции, которая отправляет электронное письмо.
Ответ №1:
После долгих исследований я нашел 2 способа добиться этого :
- Первый способ — вызвать
exports.a
вместоa
вb
функции :
functions.js
export const a = (x) => { a very complicated function };
export const b = (x) => exports.a(x 1);
functions.test.js
import * as functions from './functions';
describe('b', () => {
test('calling b calls a with x 1', () => {
functions.a = jest.fn();
functions.b(1);
expect(functions.a).toHaveBeenCalledWith(2);
});
});
});
- Второй способ — изменить прототип
b
на принимает функцию, по умолчанию наa
:
functions.js
export const a = (x) => { a very complicated function };
export const b = (x, a = exports.a) => a(x 1);
functions.test.js
import { a, b } from './functions';
describe('b', () => {
test('calling b calls a with x 1', () => {
const fakeA = jest.fn();
b(1, fakeA);
expect(fakeA).toHaveBeenCalledWith(2);
});
});
Комментарии:
1. Возвращаясь к этой проблеме снова, с этим первым подходом, как мне сбросить реализацию функции в исходную функцию, потому что последующие тесты, для которых требуется исходная функция, считают ее пустой функцией для functions.a = jest.fn(); Я пробовал clearAllMocks и resetAllMocks, и она не сбрасывается
Ответ №2:
Самый простой способ решить эту проблему — использовать метод jest.spyOn.
jest.spyOn(объект, имяметода)
Создает макет функции, похожей на jest.fn, но также отслеживает вызовы object[methodName]. Возвращает макет функции Jest.
import * as functions from '../functions';
describe('b', () => {
test('calling b calls a with x 1', () => {
const fakeA = jest.spyOn( functions, 'a' );
functions.b(1);
expect( fakeA ).toHaveBeenCalledWith(2);
});
});
Комментарии:
1. являются ли эти файлы файлами js или ts?
2. Невозможно шпионить за функцией, которая используется в том же модуле, в котором она была определена.