监视 Sinon.js 中的原型方法
Spying on a prototype method in Sinon.js
对于 sinon,我正在尝试监视原型方法。它在在线 howtos 等中看起来很简单。我尝试了很多网站和这样的帖子:Stubbing a class method with Sinon.js or sinon - spy on toString method,但它对我不起作用。
先决条件
我正在使用 http.d.ts https://github.com/nodejs/node/blob/master/lib/_http_outgoing.js 通过 OutgoingMessage
对象从异步 API 调用写回数据:
class OutgoingMessage extends stream.Writable
OutgoingMessage
中有原型方法end
:
OutgoingMessage.prototype.end = function end(chunk, encoding, callback) {
我的API函数是这样调用的:
Get = async (req:IncomingMessage,res:OutgoingMessage):Promise<void> => {...
...
res.end(data)
...
}
我的测试
在我的测试中,我调用了 Get
方法。我的 IncomingMessage
决定了我期望在 OutgoingMessage
.
中的内容
it("should call end with the correct value", async function(){
...
let outgoingMessageSpy = sinon.spy(OutgoingMessage.prototype,"end");
let anOutgoingMessage = <OutgoingMessage>{};
...
expect(outgoingMessageSpy.calledOnce).to.be.true();
}
调试测试用例我看到了如何调用 end
但显然我没有以正确的方式设置我的间谍,因为我的期望失败了,calledOnce
是 false
。检查对象我看到 calledCount
是 0
.
当我这样做时,我做的基本上是一样的(在我看来)
const toStringSpy = sinon.spy(Number.prototype, "toString");
expect(toStringSpy.calledWith(2)).to.be.true;
这行得通。不过,我确实注意到,VS Code 针对 Number.prototype
和 OutgoingMessage.prototype
以不同方式突出显示关键字 prototype
。这有关系吗?在鼠标悬停时说 NumberConstructor.prototype
但只有 OutgoingMessage.prototype
..
问题
如何正确设置间谍以获取对原型方法的调用end
?
您已正确设置间谍。 但是,有一些条件可以使间谍失败。例如:我看到您使用异步函数,也许您在异步函数测试中没有正确等待。下面的示例向您展示了该条件。
我有一个非常简单的 http 服务器,它有延迟响应。
我这样创建您的 Get 方法:
// File: get.ts
import { IncomingMessage, OutgoingMessage } from 'http';
import delay from 'delay';
const Get = async (req: IncomingMessage, res: OutgoingMessage): Promise<void> => {
console.log('Get start');
// I add this to show you that this async function need to be awaited.
await delay(200);
res.end(JSON.stringify({
data: 'Hello World!'
}));
console.log('Get finish');
};
export default Get;
然后我创建主 index.ts 文件。
// File: index.ts
import http, { IncomingMessage, OutgoingMessage } from 'http';
import Get from './get';
const server = http.createServer((req: IncomingMessage, res: OutgoingMessage) => {
console.log('Receiving IncomingMessage');
res.setHeader('Content-Type', 'application/json');
Get(req, res);
});
const port = 8000;
server.listen(port);
server.on('listening', () => {
console.log(`Listen http on ${port}`);
});
我创建测试文件:get.spec.ts
// File: get.spec.ts
import sinon from 'sinon';
import http, { OutgoingMessage } from 'http';
import { Socket } from 'net';
import { expect } from 'chai';
import Get from './get';
describe('GET', () => {
it('should call end with the correct value', async () => {
// I copy paste from your code with minor code style edit.
const outgoingMessageSpy = sinon.spy(OutgoingMessage.prototype, 'end');
const socket = new Socket();
const incoming = new http.IncomingMessage(socket);
const outgoing = new http.OutgoingMessage();
// This is just some private property which need to be set.
(outgoing as any)._header = true;
// NOTE: If you want invalid response, remove the "await".
await Get(incoming, outgoing);
// Set the debug message here before expect.
console.log('SPY Counter:', outgoingMessageSpy.callCount);
console.log('SPY CalledOnce:', outgoingMessageSpy.calledOnce);
expect(outgoingMessageSpy.calledOnce).to.be.true;
});
});
当我运行从终端使用ts-mocha时,结果是这样的:
$ npx ts-mocha get.spec.ts
GET
Get start
Get finish
SPY Counter: 1
SPY CalledOnce: true
✓ should call end with the correct value (204ms)
1 passing (206ms)
您看到您已将间谍设置为 OutgoingMessage.prototype.end 正确。
BUT,当您在测试中删除 await 时(请参阅 get.spec.ts 文件中的注释),结果如下:
$ npx ts-mocha get.spec.ts
GET
Get start
SPY Counter: 0
SPY CalledOnce: false
1) should call end with the correct value
0 passing (8ms)
1 failing
1) GET
should call end with the correct value:
AssertionError: expected false to be true
+ expected - actual
-false
+true
Get finish
条件是:end 方法被正确调用,但在 it 测试被评估之后。
对于 sinon,我正在尝试监视原型方法。它在在线 howtos 等中看起来很简单。我尝试了很多网站和这样的帖子:Stubbing a class method with Sinon.js or sinon - spy on toString method,但它对我不起作用。
先决条件
我正在使用 http.d.ts https://github.com/nodejs/node/blob/master/lib/_http_outgoing.js 通过 OutgoingMessage
对象从异步 API 调用写回数据:
class OutgoingMessage extends stream.Writable
OutgoingMessage
中有原型方法end
:
OutgoingMessage.prototype.end = function end(chunk, encoding, callback) {
我的API函数是这样调用的:
Get = async (req:IncomingMessage,res:OutgoingMessage):Promise<void> => {...
...
res.end(data)
...
}
我的测试
在我的测试中,我调用了 Get
方法。我的 IncomingMessage
决定了我期望在 OutgoingMessage
.
it("should call end with the correct value", async function(){
...
let outgoingMessageSpy = sinon.spy(OutgoingMessage.prototype,"end");
let anOutgoingMessage = <OutgoingMessage>{};
...
expect(outgoingMessageSpy.calledOnce).to.be.true();
}
调试测试用例我看到了如何调用 end
但显然我没有以正确的方式设置我的间谍,因为我的期望失败了,calledOnce
是 false
。检查对象我看到 calledCount
是 0
.
当我这样做时,我做的基本上是一样的(在我看来)
const toStringSpy = sinon.spy(Number.prototype, "toString");
expect(toStringSpy.calledWith(2)).to.be.true;
这行得通。不过,我确实注意到,VS Code 针对 Number.prototype
和 OutgoingMessage.prototype
以不同方式突出显示关键字 prototype
。这有关系吗?在鼠标悬停时说 NumberConstructor.prototype
但只有 OutgoingMessage.prototype
..
问题
如何正确设置间谍以获取对原型方法的调用end
?
您已正确设置间谍。 但是,有一些条件可以使间谍失败。例如:我看到您使用异步函数,也许您在异步函数测试中没有正确等待。下面的示例向您展示了该条件。
我有一个非常简单的 http 服务器,它有延迟响应。
我这样创建您的 Get 方法:
// File: get.ts
import { IncomingMessage, OutgoingMessage } from 'http';
import delay from 'delay';
const Get = async (req: IncomingMessage, res: OutgoingMessage): Promise<void> => {
console.log('Get start');
// I add this to show you that this async function need to be awaited.
await delay(200);
res.end(JSON.stringify({
data: 'Hello World!'
}));
console.log('Get finish');
};
export default Get;
然后我创建主 index.ts 文件。
// File: index.ts
import http, { IncomingMessage, OutgoingMessage } from 'http';
import Get from './get';
const server = http.createServer((req: IncomingMessage, res: OutgoingMessage) => {
console.log('Receiving IncomingMessage');
res.setHeader('Content-Type', 'application/json');
Get(req, res);
});
const port = 8000;
server.listen(port);
server.on('listening', () => {
console.log(`Listen http on ${port}`);
});
我创建测试文件:get.spec.ts
// File: get.spec.ts
import sinon from 'sinon';
import http, { OutgoingMessage } from 'http';
import { Socket } from 'net';
import { expect } from 'chai';
import Get from './get';
describe('GET', () => {
it('should call end with the correct value', async () => {
// I copy paste from your code with minor code style edit.
const outgoingMessageSpy = sinon.spy(OutgoingMessage.prototype, 'end');
const socket = new Socket();
const incoming = new http.IncomingMessage(socket);
const outgoing = new http.OutgoingMessage();
// This is just some private property which need to be set.
(outgoing as any)._header = true;
// NOTE: If you want invalid response, remove the "await".
await Get(incoming, outgoing);
// Set the debug message here before expect.
console.log('SPY Counter:', outgoingMessageSpy.callCount);
console.log('SPY CalledOnce:', outgoingMessageSpy.calledOnce);
expect(outgoingMessageSpy.calledOnce).to.be.true;
});
});
当我运行从终端使用ts-mocha时,结果是这样的:
$ npx ts-mocha get.spec.ts
GET
Get start
Get finish
SPY Counter: 1
SPY CalledOnce: true
✓ should call end with the correct value (204ms)
1 passing (206ms)
您看到您已将间谍设置为 OutgoingMessage.prototype.end 正确。
BUT,当您在测试中删除 await 时(请参阅 get.spec.ts 文件中的注释),结果如下:
$ npx ts-mocha get.spec.ts
GET
Get start
SPY Counter: 0
SPY CalledOnce: false
1) should call end with the correct value
0 passing (8ms)
1 failing
1) GET
should call end with the correct value:
AssertionError: expected false to be true
+ expected - actual
-false
+true
Get finish
条件是:end 方法被正确调用,但在 it 测试被评估之后。