У меня есть довольно распространенный вариант использования тестирования, и я не уверен, какой там лучший подход.
Я хотел бы протестировать модуль, который зависит от пользовательской зависимости. Пользовательская зависимость (neat-csv
) экспортирует одну функцию, которая возвращает Promise.
Я хочу neat-csv
поведение neat-csv
чтобы оно отклонялось с ошибкой для одного теста. Затем я хочу восстановить исходную реализацию модуля.
AFAIK, я не могу использовать jest.spyOn
здесь, так как модуль экспортирует одну функцию.
Поэтому я подумал, что использование ручных издевательств было присвоено, и это работает. Однако я не могу понять, как восстановить первоначальную реализацию через ручной макет.
Для простоты здесь урезанная версия модуля, которую я пытаюсь протестировать:
'use strict';
const neatCsv = require('neat-csv');
async function convertCsvToJson(apiResponse) {
try {
const result = await neatCsv(apiResponse.body, {
separator: ';'
});
return result;
} catch (parseError) {
throw parseError;
}
}
module.exports = {
convertCsvToJson
};
И вот попытка тестирования, которая не проходит во втором тесте (не смоделированная версия):
'use strict';
let neatCsv = require('neat-csv');
let { convertCsvToJson } = require('./module-under-test.js');
jest.mock('neat-csv', () =>
jest.fn().mockRejectedValueOnce(new Error('Error while parsing'))
);
const csv = 'type;part\nunicorn;horn\nrainbow;pink';
const apiResponse = {
body: csv
};
const rejectionOf = (promise) =>
promise.then(
(value) => {
throw value;
},
(reason) => reason
);
test('mocked version', async () => {
const e = await rejectionOf(convertCsvToJson(apiResponse));
expect(neatCsv).toHaveBeenCalledTimes(1);
expect(e.message).toEqual('Error while parsing');
});
test('non mocked version', async () => {
jest.resetModules();
neatCsv = require('neat-csv');
({ convertCsvToJson } = require('./module-under-test.js'));
const result = await convertCsvToJson(apiResponse);
expect(JSON.stringify(result)).toEqual(
'[{"type":"unicorn","part":"horn"},{"type":"rainbow","part":"pink"}]'
);
});
Мне интересно, предназначен ли jest для таких вещей или я иду по неправильному пути и должен вместо этого ввести neat-csv?
Каков был бы идиоматический способ справиться с этим?
Да, Jest предназначен для таких вещей.
Метод API, который вы ищете, это jest.doMock. Он предоставляет способ имитации модулей без неявного поднятия, который происходит с jest.mock, что позволяет вам макетировать в объеме тестов.
Вот рабочий пример вашего тестового кода, который показывает это:
const csv = 'type;part\nunicorn;horn\nrainbow;pink';
const apiResponse = {
body: csv
};
const rejectionOf = promise =>
promise.then(value => {
throw value;
}, reason => reason);
test('mocked version', async () => {
jest.doMock('neat-csv', () => jest.fn().mockRejectedValueOnce(new Error('Error while parsing')));
const neatCsv = require('neat-csv');
const { convertCsvToJson } = require('./module-under-test.js');
const e = await rejectionOf(convertCsvToJson(apiResponse));
expect(neatCsv).toHaveBeenCalledTimes(1);
expect(e.message).toEqual('Error while parsing');
});
test('non mocked version', async () => {
const { convertCsvToJson } = require('./module-under-test.js');
const result = await convertCsvToJson(apiResponse);
expect(JSON.stringify(result)).toEqual('[{"type":"unicorn","part":"horn"},{"type":"rainbow","part":"pink"}]');
});