Метод заглушки в том же файле, используя Sinon
Я пытаюсь выполнить модульное тестирование функции в файле, одновременно заглушая другую функцию в том же файле, но макет не применяется и вызывается реальный метод. Вот пример:
// file: 'foo.js'
export function a() {
// .....
}
export function b() {
let stuff = a(); // call a
// ...do stuff
}
И мой тест:
import * as actions from 'foo';
const aStub = sinon.stub(actions, 'a').returns('mocked return');
actions.b(); // b() is executed, which calls a() instead of the expected aStub()
4 ответа
Некоторая реструктуризация может сделать эту работу.
Я использовал общий синтаксис JS. Точно так же должно работать и в ES6.
foo.js
const factory = {
a,
b,
}
function a() {
return 2;
}
function b() {
return factory.a();
}
module.exports = factory;
test.js
const ser = require('./foo');
const sinon = require('sinon');
const aStub = sinon.stub(ser, 'a').returns('mocked return');
console.log(ser.b());
console.log(aStub.callCount);
Выход
высмеянное возвращение
1
Метод, упомянутый выше (с использованием factory
собирать функции) хорошо работает; однако, eslint не понравится использование переменной / функции, которая еще не была объявлена. Поэтому я бы порекомендовал небольшую модификацию:
// my-functions.js
export const factory = {};
export const funcA = () => {
return facory.funcB();
};
factory.funcA = funcA;
export const funcB = () => true;
factory.funcB = funcB;
// my-functions-test.js
import {factory, funcA, funcB} from './path/to/my-functions';
describe('MyFunctions | funcA', () => {
test('returns result from funcB call', () => {
const funcBStub = sinon.stub(factory, 'funcB').returns(false);
// Test that the function does not throw errors
let result;
expect(() => (result = funcA())).not.toThrow();
// Test that the return value is that of the mock rather than the original function
expect(result).toEqual(false);
// Test that the stub was called
expect(funcBStub.called).toEqual(true);
});
});
// Don't forget to test funcB independently ;)
Важным отличием является добавление функций из файла в factory
как они определены, чтобы избежать нарушения правил eslint. Единственный случай, когда это может вызвать проблемы, - это если вы попытались вызвать одну из этих функций в одном и том же файле до того, как все они были определены. Пример:
// my-functions-1.js
export const factory = {};
export const funcA = () => {
factory.funcB();
};
factory.funcA = funcA;
// Since the code execution runs from top to bottom, calling funcA here means that funcB has not yet been added to factory
funcA(); // Throws an error since factory.funcB() is not a function (yet)
export const funcB = () => true;
factory.funcB = funcB;
Я предпочитаю эту технику использования "сборщика" для вызова функций в одном и том же файле, поскольку не всегда хорошая идея создавать отдельные файлы для КАЖДОЙ функции, которую вы пишете. Часто я обнаруживаю, что создаю много связанных служебных функций, чтобы сделать мой код более читабельным, многократно используемым и компонуемым; размещение каждой функции в отдельном файле усложнит понимание кода, поскольку читатель не сможет увидеть определения этих функций, не перебирая разные файлы.
Хотя вышесказанное работает, это определенно обходной путь, так как мой линтер был быстр, чтобы сообщить.
В итоге я отделил модули и использовал proxyquire. Эта библиотека позволяет вам легко заменять любые / все экспорты теми, которые вы выбираете, включая шпионский шпион или насмешки. например:
в b.js
export const fnB = () => 'hey there!';
в a.js
import { fbB } from 'b.js';
export const fnA = () => fbB();
в a.test.js
import { noCallThru } from 'proxyquire';
const proxyquireStrict = noCallThru();
const stubB = stub().returns('forced result');
const moduleA = proxyquireStrict('a.js', {
'b.js' : { fnB: stubB }
}).fnA;
console.log(fnA()); // 'forced result'
Я столкнулся с той же проблемой и нашел один метод. Вы можете изменить свой файл foo.js на это:
// file: 'foo.js'
export function a() {
// .....
}
export function b() {
let stuff = exports.a(); // using "exports." to call a
// ...do stuff
}
См. Https://codeburst.io/stub-dependencies-with-sinon-js-259ac12379b9 .