我有一台小型服务器,可以从机器接收数据。每次收到消息时,我都会在调度程序对象中调用一个函数,只是console.log
它收到的所有内容。
代码运行良好,因为我可以在控制台中看到console.log
,但Sinon spy.called
不起作用。无论我拨打false
多少次,它总是dispatcher.onMessage
。
server.js
const eventDispatcher = {
onMessage: console.log,
};
const server = (dispatcher = eventDispatcher) => {
//this gets called everytime the server receives a message
const onData = data => {
//Process data
//....
dispatcher.onMessage(data);
};
const getDispatcher = () => dispatcher;
return Object.freeze({
getDispatcher
});
};
test.js
describe("message sender", () => {
const myServer = serverFactory();
it("should send information to server", () => {
dummyMachine.socket.write("Hello World!\r\n");
const dataSpy = sinon.spy(myServer.getDispatcher(), "onMessage");
expect(dataSpy.called).to.be.true; //always fails!
});
});
在阅读类似的帖子之后,我相信这是由于某些间接层发生的,如下所示:
应该使用this
修复:
然而,看着我的代码,我真的无法得到我所缺少的东西。
目录结构
Project_Folder
|____package.json
|____server.js
|____test
|____ dummyMachine_spec.js
的package.json
{
"name": "sinon-question",
"version": "1.0.0",
"description": "MCVE about a dummy machine connecting to a server for StackOverflow",
"main": "server.js",
"scripts": {
"test": "NODE_ENV=test mocha --reporter spec --slow 5000 --timeout 5000 test/*_spec.js || true"
},
"author": "Pedro Miguel P. S. Martins",
"license": "ISC",
"devDependencies": {
"chai": "^3.5.0",
"mocha": "^3.3.0",
"sinon": "^2.2.0"
},
"dependencies": {
"net": "^1.0.2"
}
}
server.js
"use strict";
const net = require("net");
const eventDispatcher = {
onMessage: console.log,
};
const server = (dispatcher = eventDispatcher) => {
let serverSocket;
const onData = data => {
//Process data
dispatcher.onMessage(`I am server and I got ${data}`);
};
const start = (connectOpts) => {
return new Promise(fulfil => {
serverSocket = net.createConnection(connectOpts, () => {
serverSocket.on("data", onData);
fulfil();
});
});
};
const stop = () => serverSocket.destroy();
const getDispatcher = () => dispatcher;
return Object.freeze({
start,
stop,
getDispatcher
});
};
module.exports = server;
测试/ dummyMachine.js
"use strict";
const chai = require("chai"),
expect = chai.expect;
const sinon = require("sinon");
const net = require("net");
const serverFactory = require("../server.js");
describe("Dummy Machine", () => {
const dummyMachine = {
IP: "localhost",
port: 4002,
server: undefined,
socket: undefined
};
const server = serverFactory();
before("Sets up dummyReader and server", done => {
dummyMachine.server = net.createServer(undefined, socket => {
dummyMachine.socket = socket;
});
dummyMachine.server.listen(
dummyMachine.port,
dummyMachine.IP,
undefined,
() => {
server.start({
host: "localhost",
port: 4002
})
.then(done);
}
);
});
after("Kills dummyReader and server", () => {
server.stop();
dummyMachine.server.close();
});
it("should connect to server", done => {
dummyMachine.server.getConnections((err, count) => {
expect(err).to.be.null;
expect(count).to.eql(1);
done();
});
});
it("should send information to server", () => {
dummyMachine.socket.write("Hello World\r\n");
const dataSpy = sinon.spy(server.getDispatcher(), "onMessage");
expect(dataSpy.called).to.be.true; //WORK DAAMN YOU!
});
});
npm install
npm test
第一个测试应该通过,这意味着实际上正在进行连接。
即使您获得了控制台日志,第二次测试也会失败,证明onMessage
已被调用。
答案 0 :(得分:1)
主要问题是仅仅监视onMessage
是不够的,因为你的测试在完全被调用时永远不会找到(因为流事件是异步的)递送)。
您可以使用setTimeout()
进行黑客攻击,并在向服务器发送消息后检查并查看它是否被调用,但这并不理想。
相反,您可以将onMessage
替换为将被调用的函数,并且从该函数中,您可以测试并查看是否使用正确的参数调用它等。
Sinon提供stubs可用于此目的:
it("should send information to server", done => {
const stub = sinon.stub(server.getDispatcher(), 'onMessage').callsFake(data => {
stub.restore();
expect(data).to.equal('I am server and I got Hello World\r\n');
done();
});
dummyMachine.socket.write("Hello World\r\n");
});
而不是原始onMessage
,它将调用"假函数"你提供的。在那里,存根被恢复(这意味着onMessage
恢复到其原始状态),您可以检查并查看是否使用正确的参数调用它。
由于测试是异步的,因此使用done
。
有几件事需要考虑:
onMessage
无法在所有中调用,因此您无法轻松检测到。当发生这种情况时,几秒钟后,Mocha将超时测试,导致测试失败。onMessage
的后续测试都将失败,因为该方法已经存根(通常,您可以通过创建onBeforeEach
中的存根,并将其恢复为onAfterEach
)onMessage
的内部工作原理,因为它已被替换。{li>它只测试它是否被调用,并且使用正确的参数(但是,它更好,更容易,单独测试onMessage
,通过直接使用测试用例中的各种参数调用它。)答案 1 :(得分:0)
我猜这个问题是由你想要侦察的对象使用Object.freeze
造成的。
大部分时间这些"间谍"技术通过用另一个实现" spying"的函数覆盖sped on function来工作。功能(例如:跟踪函数调用)。
但是,如果您要冻结对象,则无法覆盖该功能。