Я хотел бы изменить реализацию фиктивной зависимости для каждого отдельного теста , расширив поведение макета по умолчанию и вернув его обратно к исходной реализации при выполнении следующего теста.
Короче вот чего я пытаюсь достичь:
- имитация зависимости
- изменить / расширить реализацию макета за один тест
- вернуться к исходному макету при выполнении следующего теста
Я сейчас использую Jest v21
.
Вот как будет выглядеть типичный тест Jest:
__mocks__/myModule.js
const myMockedModule = jest.genMockFromModule('../myModule');
myMockedModule.a = jest.fn(() => true);
myMockedModule.b = jest.fn(() => true);
export default myMockedModule;
__tests__/myTest.js
import myMockedModule from '../myModule';
// Mock myModule
jest.mock('../myModule');
beforeEach(() => {
jest.clearAllMocks();
});
describe('MyTest', () => {
it('should test with default mock', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
it('should override myMockedModule.b mock result (and leave the other methods untouched)', () => {
// Extend change mock
myMockedModule.a(); // === true
myMockedModule.b(); // === 'overridden'
// Restore mock to original implementation with no side effects
});
it('should revert back to default myMockedModule mock', () => {
myMockedModule.a(); // === true
myMockedModule.b(); // === true
});
});
Вот что я пробовал до сих пор:
1 - mockFn.mockImplementationOnce (fn)
плюсы
- Возврат к исходной реализации после первого вызова
минусы
- Он ломается, если тест вызывает
b
несколько раз - Он не возвращается к исходной реализации, пока
b
не будет вызван (утечка в следующем тесте)
код:
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
myMockedModule.b.mockImplementationOnce(() => 'overridden');
myModule.a(); // === true
myModule.b(); // === 'overridden'
});
2 - jest.doMock (имя модуля, завод, параметры)
плюсы
- Явно перепроверяет имитацию при каждом тесте
минусы
- Невозможно определить реализацию макета по умолчанию для всех тестов
- Невозможно расширить реализацию по умолчанию, заставив повторно объявить каждый фиктивный метод
код:
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
jest.doMock('../myModule', () => {
return {
a: jest.fn(() => true,
b: jest.fn(() => 'overridden',
}
});
myModule.a(); // === true
myModule.b(); // === 'overridden'
});
3 - Ручной имитатор с помощью методов установки (как описано здесь )
плюсы
- Полный контроль над фиктивными результатами
минусы
- Лот шаблонного кода
- Трудно поддерживать в течение длительного времени
код:
__mocks__/myModule.js
const myMockedModule = jest.genMockFromModule('../myModule');
let a = true;
let b = true;
myMockedModule.a = jest.fn(() => a);
myMockedModule.b = jest.fn(() => b);
myMockedModule.__setA = (value) => { a = value };
myMockedModule.__setB = (value) => { b = value };
myMockedModule.__reset = () => {
a = true;
b = true;
};
export default myMockedModule;
__tests__/myTest.js
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
myModule.__setB('overridden');
myModule.a(); // === true
myModule.b(); // === 'overridden'
myModule.__reset();
});
4 - jest.spyOn (объект, имя метода)
минусы
- Я не могу вернуться
mockImplementation
к исходному фиктивному возвращаемому значению, что влияет на следующие тесты
код:
beforeEach(() => {
jest.clearAllMocks();
jest.restoreAllMocks();
});
// Mock myModule
jest.mock('../myModule');
it('should override myModule.b mock result (and leave the other methods untouched)', () => {
const spy = jest.spyOn(myMockedModule, 'b').mockImplementation(() => 'overridden');
myMockedModule.a(); // === true
myMockedModule.b(); // === 'overridden'
// How to get back to original mocked value?
});
javascript
unit-testing
mocking
jestjs
Андреа Карраро
источник
источник
Ответы:
Хорошим шаблоном для написания теста является создание функции фабрики настройки, которая возвращает данные, необходимые для тестирования текущего модуля.
Ниже приведен пример кода, следующий за вашим вторым примером, хотя он позволяет повторно использовать значения по умолчанию и переопределить.
const spyReturns = returnValue => jest.fn(() => returnValue); describe("scenario", () => { const setup = (mockOverrides) => { const mockedFunctions = { a: spyReturns(true), b: spyReturns(true), ...mockOverrides } return { mockedModule: jest.doMock('../myModule', () => mockedFunctions) } } it("should return true for module a", () => { const { mockedModule } = setup(); expect(mockedModule.a()).toEqual(true) }); it("should return override for module a", () => { const EXPECTED_VALUE = "override" const { mockedModule } = setup({ a: spyReturns(EXPECTED_VALUE)}); expect(mockedModule.a()).toEqual(EXPECTED_VALUE) }); });
источник
Ванильный JS
Используйте mockFn.mockImplementation (fn) .
import { funcToMock } from './somewhere'; jest.mock('./somewhere'); beforeEach(() => { funcToMock.mockImplementation(() => { /* default implementation */ }); }); test('case that needs a different implementation of funcToMock', () => { funcToMock.mockImplementation(() => { /* implementation specific to this test */ }); // ... });
Машинопись
Чтобы сообщение mockImplementation не было свойством funcToMock , вам необходимо указать тип, например, изменив верхнюю строку сверху на следующую:
import { (funcToMock as jest.Mock) } from './somewhere';
Вопрос, касающийся этой проблемы, можно найти здесь: макет свойства jest typescript не существует для типа
источник
Немного поздно на вечеринку, но если у кого-то есть проблемы с этим.
Мы используем TypeScript, ES6 и babel для разработки на основе реакции.
Обычно мы имитируем внешние модули NPM в корневом
__mocks__
каталоге.Я хотел переопределить определенную функцию модуля в классе Auth aws-ampify для конкретного теста.
import { Auth } from 'aws-amplify'; import GetJwtToken from './GetJwtToken'; ... it('When idToken should return "123"', async () => { const spy = jest.spyOn(Auth, 'currentSession').mockImplementation(() => ({ getIdToken: () => ({ getJwtToken: () => '123', }), })); const result = await GetJwtToken(); expect(result).toBe('123'); spy.mockRestore(); });
Суть: https://gist.github.com/thomashagstrom/e5bffe6c3e3acec592201b6892226af2
Учебник: https://medium.com/p/b4ac52a005d#19c5
источник