Javascript 西农间谍公司称不工作 背景
我有一个从机器接收数据的小型服务器。每次收到消息时,我都会调用dispatcher对象中的一个函数,该函数只是Javascript 西农间谍公司称不工作 背景,javascript,node.js,testing,sinon,Javascript,Node.js,Testing,Sinon,我有一个从机器接收数据的小型服务器。每次收到消息时,我都会调用dispatcher对象中的一个函数,该函数只是console.logs它接收到的所有内容 问题 代码运行良好,我可以在控制台中看到console.logs,但是Sinonspy.called不起作用。无论我调用了多少次dispatcher.onMessage,它总是false 代码 server.js const eventDispatcher = { onMessage: console.log, }; const se
console.log
s它接收到的所有内容
问题
代码运行良好,我可以在控制台中看到console.log
s,但是Sinonspy.called
不起作用。无论我调用了多少次dispatcher.onMessage,它总是false
代码
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
});
};
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!
});
});
"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;
"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!
});
});
test.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
});
};
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!
});
});
"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;
"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!
});
});
研究
在阅读了类似的文章后,我认为这是由于某种间接因素造成的,如:
- 我做错了什么
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
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
});
};
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!
});
});
"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;
"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!
});
});
测试/dummyMachine.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
});
};
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!
});
});
"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;
"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!
});
});
MCVE使用说明
npm install
npm测试
第二个测试将失败,即使您获得了控制台日志,证明调用了
onMessage
。我猜问题是由于在您想要监视的对象上使用对象。冻结
大多数情况下,这些“监视”技术通过使用另一个实现“监视”功能的函数(例如:跟踪函数调用)覆盖监视函数来工作
但是,如果冻结对象,则无法覆盖该函数。主要问题是,仅监视消息上的
是不够的,因为您的测试永远无法确定它何时被准确调用(因为流事件是异步传递的)
您可以使用hack使用setTimeout()
,并检查它是否在向服务器发送消息后被调用,但这并不理想
相反,您可以用一个将被调用的函数替换onMessage
,从该函数中,您可以测试并查看它是否被正确的参数调用,等等
Sinon提供了可用于此目的的:
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
的任何后续测试都将失败,因为该方法已经存根(通常,您可以通过在每个
之前的中创建存根,然后在每个
之后的中恢复存根来解决此问题)
此解决方案不会测试消息
的内部工作,因为它正在被替换。它只在调用它时进行测试,并且使用正确的参数(但是,通过使用测试用例中的各种参数直接调用它,单独测试onMessage
会更好、更容易)
移除冻结不会修复任何东西(已测试)。此外,如果这是问题所在,在测试运行之前,我实际上会有一个运行时错误,而事实并非如此!那么,
onMessage
会在哪里被调用呢?在创建spy和检查它是否被调用之间,我看不到任何其他代码正在运行。console.log显示,间谍无法工作…您正在创建间谍并立即检查它是否被调用。Node.js不是多线程的,因此在这两个操作之间没有上下文切换(即服务器接收任何内容的时间)。这让我很困惑。你是在告诉我,如果我做一个1秒的setTimeout
,然后尝试调用spy,它会工作吗?可能会,但解决这个问题的正确方法是实现一个异步测试。但是,您在此处发布的代码没有提供足够的洞察力来确定应用程序中的所有内容是如何连接的。例如,dummyMachine.socket.write()
在做什么?考虑创建一个惊人的输入!我用了你答案的变体。这正是我需要的!