I am not able to increase the test coverage/test function which is invoked by a child process on exit. And I want to mock fork('src/services/ssync-process.js');
log.info('Child process sProcessJob finished execution'); sProcess.kill();
are never covered
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();
});
}
};
Here is the unit test solution using Link Seams, proxyquire package and rewire package.
E.g.
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);
});
});
The first test case uses proxyquire
to test, the second test case uses rewire
to test.
Unit test results with 100% coverage:
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 |
----------|---------|----------|---------|---------|-------------------