javascript - 在测试子类时,如何监视祖父类中的导入函数?
问题描述
我无法监视从节点模块导入的函数。我正在测试一个子类,并且模块被导入到祖父类中,我需要查看调用该函数的参数。
代码按预期工作,但我已经用 Jasmine 的内置测试过,但spyOn
也sinon.spy
没有调用任何间谍。
代码:
// ChildClass.js
const ParentClass = require('./ParentClass');
module.exports = class ChildClass extends ParentClass {
constructor () {
super();
this.foo();
}
foo () {
this.message = this.importGetter('Some input');
}
};
// ParentClass.js
const GrandparentClass = require('./GrandparentClass');
module.exports = class ParentClass extends GrandparentClass {
constructor () {
super();
this._message = null;
}
get message () {
return this._message;
}
set message (value) {
this._message = value;
}
};
// GrandparentClass.js
const nodeModuleFunction = require('./nodeModule').nodeModuleFunction;
module.exports = class GrandparentClass {
get importGetter () {
return nodeModuleFunction;
}
};
// nodeModule.js
async function nodeModuleFunction (input) {
console.error('Do something with input: ', input);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Returned from node module.');
}, 300);
});
}
exports.nodeModuleFunction = nodeModuleFunction;
测试代码:
// test.spec.js
const ChildClass = require('./ChildClass');
const nodeModule = require('./nodeModule');
const sinon = require('sinon');
describe('ChildClass test', () => {
describe('Jasmine spy', () => {
it('should call nodeModule.nodeModuleFunction with given value', done => {
spyOn(nodeModule, 'nodeModuleFunction').and.callThrough();
const object = new ChildClass();
expect(object.message).not.toBeNull();
expect(nodeModule.nodeModuleFunction).toHaveBeenCalled();
expect(nodeModule.nodeModuleFunction).toHaveBeenCalledWith('Some input');
object.message.then(message => {
expect(message).toBe('Returned from node module.');
done();
});
});
});
describe('Sinon spy', () => {
it('should call nodeModule.nodeModuleFunction with given value', done => {
const spy = sinon.spy(nodeModule, 'nodeModuleFunction');
const object = new ChildClass();
expect(object.message).not.toBeNull();
expect(spy.called).toBe(true);
expect(spy.withArgs('Some input').calledOnce).toBe(true);
object.message.then(message => {
expect(message).toBe('Returned from node module.');
done();
});
});
});
});
试验结果:
Jasmine started
Do something with input: Some input
ChildClass test
Jasmine spy
✗ should call nodeModule.nodeModuleFunction with given value
- Expected spy nodeModuleFunction to have been called.
- Expected spy nodeModuleFunction to have been called with [ 'Some input' ] but it was never called.
Do something with input: Some input
Sinon spy
✗ should call nodeModule.nodeModuleFunction with given value
- Expected false to be true.
- Expected false to be true.
按照布赖恩的建议使用解决方案进行编辑:
const nodeModule = require('./nodeModule');
describe('ChildClass test', () => {
let ChildClass;
beforeAll(() => {
spyOn(nodeModule, 'nodeModuleFunction').and.callThrough(); // create the spy...
ChildClass = require('./ChildClass'); // ...and now require ChildClass
});
afterEach(() => {
nodeModule.nodeModuleFunction.calls.reset();
});
describe('Jasmine spy', () => {
it('should call nodeModule.nodeModuleFunction with given value', done => {
const object = new ChildClass();
expect(object.message).not.toBeNull();
expect(nodeModule.nodeModuleFunction).toHaveBeenCalled();
expect(nodeModule.nodeModuleFunction).toHaveBeenCalledWith('Some input');
object.message.then(message => {
expect(message).toBe('Returned from node module.');
done();
});
});
it('should still call nodeModule.nodeModuleFunction with given value', done => {
const object = new ChildClass();
expect(object.message).not.toBeNull();
expect(nodeModule.nodeModuleFunction).toHaveBeenCalled();
expect(nodeModule.nodeModuleFunction).toHaveBeenCalledWith('Some input');
object.message.then(message => {
expect(message).toBe('Returned from node module.');
done();
});
});
});
});
const nodeModule = require('./nodeModule');
const sinon = require('sinon');
describe('ChildClass test', () => {
let spy;
let ChildClass;
beforeAll(() => {
spy = sinon.spy(nodeModule, 'nodeModuleFunction'); // create the spy...
ChildClass = require('./ChildClass'); // ...and now require ChildClass
});
afterEach(() => {
spy.resetHistory();
});
afterAll(() => {
spy.restore();
});
describe('Sinon spy', () => {
it('should call nodeModule.nodeModuleFunction with given value', done => {
const object = new ChildClass();
expect(object.message).not.toBeNull();
expect(spy.called).toBe(true);
expect(spy.withArgs('Some input').calledOnce).toBe(true);
object.message.then(message => {
expect(message).toBe('Returned from node module.');
done();
});
});
it('should still call nodeModule.nodeModuleFunction with given value', done => {
const object = new ChildClass();
expect(object.message).not.toBeNull();
expect(spy.called).toBe(true);
expect(spy.withArgs('Some input').calledOnce).toBe(true);
object.message.then(message => {
expect(message).toBe('Returned from node module.');
done();
});
});
});
});
解决方案
GrandparentClass.js
要求并在运行后立即获取对...nodeModule.js
的引用nodeModuleFunction
...所以你只需要确保你的间谍在它运行之前就位:
const nodeModule = require('./nodeModule');
const sinon = require('sinon');
describe('ChildClass test', () => {
describe('Sinon spy', () => {
it('should call nodeModule.nodeModuleFunction with given value', done => {
const spy = sinon.spy(nodeModule, 'nodeModuleFunction'); // create the spy...
const ChildClass = require('./ChildClass'); // ...and now require ChildClass
const object = new ChildClass();
expect(object.message).not.toBeNull(); // Success!
expect(spy.called).toBe(true); // Success!
expect(spy.withArgs('Some input').calledOnce).toBe(true); // Success!
object.message.then(message => {
expect(message).toBe('Returned from node module.'); // Success!
done();
});
});
});
});
我更新了Sinon
测试,但该方法也适用于Jasmine
测试。
推荐阅读
- php - Ajax Post:使用 document.location 进行 API 响应重定向无法正常工作
- angular - 类型错误:val 不可迭代
- c - 在链表中搜索字符串 C
- java - 如何在不同集合的集合中创建对象流
- javascript - 需要帮助将 Stripe 内联 Javascript 移动到项目的 .js 文件
- flutter - 将状态实例提供给另一个类
- python - 使用“从 PyQt5 导入 uic”时,pyinstaller exe 冻结
- reactjs - 从 Jest 生成文本摘要报告
- python - 如何在 Pytorch 中有效地连接两层的输出?
- python - 如何在指数级大列表中找到第 k 个最大的元素?