Вопрос сформулирован таким образом, поскольку я могу войти в тестируемый код в среде IDE, и фактический код работает, как и ожидалось, но тест не проходит.
К тестированию HTML с помощью <script src = "../example.js"></script>
прикреплен файл javascript, и его содержимое выглядит так:
function myFunc(myId) {
console.info(myId);
}
function someOtherFunc(arg) {
if (arg == 0)
myFunc("#id_0");
else
myFunc("#id_1");
}
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * *
* SECTION: exports needed by jest testing framework
* * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
if (typeof exports !== 'undefined') {
module.exports = {
myFunc,
someOtherFunc,
};
}
А ниже приведено упрощенное содержимое модуля тестирования example.test.js
с одним из (многих) неудачных способов протестировать этот вызов:
const fs = require('fs');
const path = require('path');
const html = fs.readFileSync(path.resolve(__dirname, './example.html'), 'utf8');
const jquery = require('../../static/js/jquery-2.2.4.min.js');
window.$ = jquery;
window.jQuery = jquery;
const mockSend = jest.fn();
global.WebSocket = jest.fn();
global.WebSocket.mockImplementation(() => {
return {
send: mockSend,
};
});
const example = require('../example.js');
jest
.dontMock('fs');
beforeEach(() => {
document.documentElement.innerHTML = html.toString();
});
afterEach(() => {
jest.resetModules();
});
describe('someOtherFunc function', function () {
it('calls myFunc', function () {
const spyFunc = jest.spyOn(example, "myFunc");
const result = example.someOtherFunc(0);
expect(spyFunc).toHaveBeenCalledWith("#id_0")
});
});
Я вставил эту часть mockSend
сюда, так как мне удалось успешно протестировать ее с помощью expect(mockSend).toHaveBeenCalledWith("...");
. Этот метод send
также находится внутри другой функции, и я тестирую вызывающую функцию в модуле jest.
Однако я не могу найти способ пройти этот тест «вызовы myFunc».
@Chandan, можешь ли ты добавить это в качестве ответа, чтобы я мог его принять?
Заглушка функции в Javascript требует, чтобы функция была привязана к контексту, любому контексту, который находится в области действия как тестового кода, так и тестируемого кода. В нормальном мире этот контекст предоставляется модулем. Например, в ES5 Node.js:
exports.fn = функция () {}
Чего следует избегать в ES5, так это переопределения module.exports с помощью функции. Слишком много людей делают это, и это неуместно, так как любой модуль, использующий этот код, должен затем предпринять дополнительные шаги, чтобы быть полезным для модульного тестирования:
модуль.экспорт = функция () {}
Как вы можете прочитать из описания, это не работает, потому что myFunc
привязан к example.js
контексту файла.
Это сработало бы, если бы:
example.js
, например импорт модуля path
Примечание: Для получения более подробной информации вы можете перейти здесь
По описанию решение будет примерно таким:
myFunc.js
function myFunc(myId) {
console.info(myId);
}
if (typeof exports !== 'undefined') {
module.exports = myFunc;
}
пример.js
var myFunc = require('./myFunc'); // This needs to be imported using script tag for browser
function someOtherFunc(arg) {
console.info('inside', myFunc);
if (arg == 0)
myFunc("#id_0");
else
myFunc("#id_1");
}
if (typeof exports !== 'undefined') {
module.exports = {
someOtherFunc
};
}
пример.test.js
const example = require('../example.js');
const myFunc = require('../myFunc.js');
jest.mock('../myFunc.js');
afterEach(() => {
jest.resetModules();
});
describe('someOtherFunc function', function () {
it('calls myFunc', function () {
const result = example.someOtherFunc(0);
expect(myFunc).toHaveBeenCalledWith("#id_0")
});
});
пример.js
function myFunc(myId) {
console.info(myId);
}
function someOtherFunc(arg) {
if (arg == 0)
my_functions.myFunc("#id_0");
else
my_functions.myFunc("#id_1");
}
const my_functions = {
myFunc,
someOtherFunc,
};
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * *
* SECTION: exports needed by jest testing framework
* * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
if (typeof exports !== 'undefined') {
module.exports = my_functions;
}
пример.test.js
const example = require('../example');
afterEach(() => {
jest.resetModules();
});
describe('someOtherFunc function', function () {
it('calls myFunc', function () {
const spyFunc = jest.spyOn(example, "myFunc");
const result = example.someOtherFunc(0);
expect(spyFunc).toHaveBeenCalledWith("#id_0")
});
});
пакет.json
{
"name": "65287977",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"babel-jest": "^26.6.3",
"jest": "^26.6.3",
},
}
Babel.config.js
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
esmodules: true
}
}
],
],
};
Извините, я не могу этого понять. Я могу понять, что это решает вызов jest.spyOn(example, "someOtherFunc")
, но как я могу использовать этот «промежуточный программный код» invokeExample для перехвата вызовов jest.spyOn(example, "myFunc")
? Кроме того, я не могу понять эту часть «как импорт модуля пути».
@ipaleka я обновил свой ответ с примером изменений, необходимых в коде для справки
Спасибо за ваше время. Я приму этот ответ только благодаря вашим усилиям, но до сих пор не могу найти способ проверить вызов функции из другой функции в том же модуле.
@ipaleka я добавил еще одно решение, с помощью которого вы можете проверить вызов функции из другой функции в том же модуле.
Молодец, большое спасибо! Все дело в запланированном тестировании с самого начала, и это решение доказывает это.
чтобы это работало, вам нужно написать дополнительный код, вы можете проверить это для более подробной информации.