如何测试出口事件中childporcess.on中的侦听器函数



我无法增加子进程在退出时调用的测试覆盖率/测试函数。我想模拟fork('src/services/ssyncprocess.js'(;

log.info('子进程ProcessJob已完成执行'(;sProcess.kill((;

从未覆盖

Test.js

const sinon = require('sinon');
const rewire = require('rewire');
const { EventEmitter } = require('events');
const job = rewire('../../src/services/job');
it('test exit', () => {
const mockChildProcess = new EventEmitter();
mockChildProcess.emit('exit');
mockChildProcess.kill = sinon.stub();
mockChildProcess.killed = true;
job.__set__({
sProcess: mockChildProcess,
});
job.sSyncJob();
});

Job.js

const { fork } = require('child_process');
let sProcess;
const sSyncJob = () => {
if (!sProcess || sProcess.killed) {
sProcess = fork('src/services/ssync-process.js');
sProcess.send({ hello: 'world' });
sProcess.on('message', (msg) => {
log.info('Message from child', msg);
});
sProcess.on('exit', () => {
log.info('Child process sProcessJob finished execution');
sProcess.kill();
});
}
};

这是使用Link Seams、proxyquire包和rewire包的单元测试解决方案。

例如

job.js:

let { fork } = require('child_process');
const log = {
info: console.info,
};
let sProcess;
const sSyncJob = () => {
if (!sProcess || sProcess.killed) {
sProcess = fork('src/services/ssync-process.js');
sProcess.send({ hello: 'world' });
sProcess.on('message', (msg) => {
log.info('Message from child', msg);
});
sProcess.on('exit', () => {
log.info('Child process sProcessJob finished execution');
sProcess.kill();
});
}
};
exports.sSyncJob = sSyncJob;

job.test.js:

const sinon = require('sinon');
const proxyquire = require('proxyquire');
const rewire = require('rewire');
describe('61561718', () => {
afterEach(() => {
sinon.restore();
});
it('should receive message', () => {
const logSpy = sinon.spy(console, 'info');
const child_process_fork_stub = {
send: sinon.stub().returnsThis(),
on: sinon
.stub()
.returnsThis()
.yields('fake message'),
kill: sinon.stub(),
};
const child_process_stub = {
fork: sinon.stub().returns(child_process_fork_stub),
};
const job = proxyquire('./job', {
child_process: child_process_stub,
});
job.sSyncJob();
sinon.assert.calledWithExactly(child_process_stub.fork, 'src/services/ssync-process.js');
sinon.assert.calledWithExactly(child_process_fork_stub.send, { hello: 'world' });
sinon.assert.calledWithExactly(child_process_fork_stub.on, 'message', sinon.match.func);
sinon.assert.calledWithExactly(child_process_fork_stub.on, 'exit', sinon.match.func);
sinon.assert.calledWithExactly(logSpy, 'Message from child', 'fake message');
sinon.assert.calledWithExactly(logSpy, 'Child process sProcessJob finished execution');
sinon.assert.calledOnce(child_process_fork_stub.kill);
});
it('should not fork child process if sProcess exists', () => {
const job = rewire('./job');
const child_process_stub = {
fork: sinon.stub(),
};
job.__set__({
sProcess: {},
child_process: child_process_stub,
});
job.sSyncJob();
sinon.assert.notCalled(child_process_stub.fork);
});
});

第一个测试用例使用proxyquire进行测试,第二个测试用例则使用rewire进行测试。

100%覆盖率的单元测试结果:

61561718
Message from child fake message
Child process sProcessJob finished execution
✓ should receive message
✓ should not fork child process if sProcess exists

2 passing (52ms)
----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |                   
job.js   |     100 |      100 |     100 |     100 |                   
----------|---------|----------|---------|---------|-------------------