Я хочу издеваться над Math.random для определенных тестов и использовать его оригинальную реализацию для других тестов. Как я могу этого добиться? Я читал об использовании jest.doMock
и jest.dontMock
, но столкнулся с рядом проблем при их использовании, например:
require
, чтобы использовать doMock
и dontMock
, но
мой проект использует только модули ES6 для импорта модулейMath
.
Я получаю сообщение об ошибке при попытке использовать jest.doMock("Math.random")
, что
результаты в Cannot find module 'Math' from 'app.test.js'
Мне не обязательно использовать doMock
и dontMock
для моих тестов. Они просто казались наиболее близкими вещами, которые я мог найти в документации по шуткам, к тому, чего я хочу достичь. Но я открыт для альтернативных решений.
Моя функция, которую я хочу протестировать внутри app.js...
export function getRandomId(max) {
if (!Number.isInteger(max) || max <= 0) {
throw new TypeError("Max is an invalid type");
}
return Math.floor(Math.random() * totalNumPeople) + 1;
}
Внутри app.test.js...
describe("getRandomId", () => {
const max = 10;
Math.random = jest.fn();
test("Minimum value for an ID is 1", () => {
Math.mockImplementationOnce(() => 0);
const id = app.getRandomId(max);
expect(id).toBeGreaterThanOrEqual(1);
});
test("Error thrown for invalid argument", () => {
// I want to use the original implementation of Math.random here
expect(() => getRandomId("invalid")).toThrow();
})
});
Попробуй это:
describe("getRandomId", () => {
const max = 10;
let randomMock;
beforeEach(() => {
randomMock = jest.spyOn(global.Math, 'random');
});
test("Minimum value for an ID is 1", () => {
randomMock.mockReturnValue(0);
const id = getRandomId(max);
expect(id).toBeGreaterThanOrEqual(1);
});
test("Error thrown for invalid argument", () => {
// I want to use the original implementation of Math.random here
randomMock.mockRestore(); // restores the original (non-mocked) implementation
expect(() => getRandomId("invalid")).toThrow();
})
});
Спасибо, это было очень полезно! Однако я заметил странное поведение при использовании mockRestore
во втором тесте. Из любопытства захотелось посмотреть, что же вернул Math.random
после восстановления randomMock
. Поэтому я поставил expect(randomMock).toHaveReturnedWith(20)
, чтобы сделать тест непройденным и посмотреть, что Math.Random
на самом деле вернул. Как ни странно, тест провалился, потому что Math.Random
вообще не вызывался.
Если я вместо этого использую mockReturnValueOnce(0)
для первого теста и заменю mockRestore
на mockClear
во втором тесте, проблема будет решена. Результаты показывают, что Math.Random
вызывается с исходной реализацией. Вы случайно не знаете, почему mockRestore
не вызвали Math.Random
?
Причина, по которой это работает с вашей модификацией, заключается в том, что mockReturnValueOnce(0)
восстановит макет после первого вызова Math.random
. Восстановление randomMock
просто означает, что любые последующие вызовы Math.random()
не будут имитироваться. но randomMock
больше нельзя использовать, так как он потерял привязку к Math.random
Вы можете проверить, что ответ работает должным образом, добавив console.info(getRandomId(42)
в оба теста (после насмешки в первом тесте и после восстановления во втором тесте). Запуск теста всегда будет печатать 1 в первом тесте и случайное целое число (в заданных границах) во втором случае.
Это хорошо знать! Я не понимал, что randomMock
потеряет свою привязку к Math.Random
после вызова mockRestore
. Я также смог проверить это поведение при запуске моих тестов. Спасибо за объяснение.
Вы смотрели jestjs.io/docs/en/mock-function-api#mockfnmockreset и jestjs.io/docs/en/mock-functions#mocking-modules?