为第三方 cli 包编写单元测试用例
Writing unit test case for third party cli package
我有一个使用 yargs 构建的基本 CLI 程序。我能够涵盖应用程序中导出函数的测试用例。
正如您在下面看到的那样,测试覆盖率并未从第 12-18
行完成。我们如何为像 yargs
这样的第三方包编写单元测试覆盖率?
index.js
const yargs = require('yargs');
const { hideBin } = require('yargs/helpers');
const greet = (name) => {
return `Welcome ${name}`;
};
yargs(hideBin(process.argv)).command(
'run [name]',
'print name',
(yargs) => {
yargs.positional('name', { describe: 'Your name', type: 'string' });
},
(args) => {
const { name } = args;
const greetMsg = greet(name);
console.log(greetMsg);
}
).argv;
module.exports = { greet };
index.test.js
const { greet } = require('./index')
describe.only('greeting', () => {
it('greet', async () => {
const greetMsg = greet('test')
expect(greetMsg).toBe('Welcome test')
})
})
测试覆盖率
PASS ./index.test.js
greeting
✓ greet (5 ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 63.64 | 100 | 33.33 | 63.64 |
index.js | 63.64 | 100 | 33.33 | 63.64 | 12-18
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.316 s, estimated 2 s
Ran all test suites.
您可以使用 jest.doMock(moduleName, factory, options) to mock yargs
and yargs/helpers
module. Since the yargs
function in the module scope will be executed when requiring the module. You need to use jest.resetModules() 重置模块注册表 - 在需要 index.js
模块之前每个测试用例的所有必需模块的缓存。
This is useful to isolate modules where local state might conflict between tests.
例如
index.js
:
const yargs = require('yargs');
const { hideBin } = require('yargs/helpers');
const greet = (name) => {
return `Welcome ${name}`;
};
yargs(hideBin(process.argv)).command(
'run [name]',
'print name',
(yargs) => {
yargs.positional('name', { describe: 'Your name', type: 'string' });
},
(args) => {
const { name } = args;
const greetMsg = greet(name);
console.log(greetMsg);
}
).argv;
module.exports = { greet };
index.test.js
:
describe.only('greeting', () => {
beforeEach(() => {
jest.resetModules();
});
it('greet', () => {
const { greet } = require('./index');
const greetMsg = greet('test');
expect(greetMsg).toBe('Welcome test');
});
it('should pass', () => {
jest.doMock('yargs');
jest.doMock('yargs/helpers');
const yargs = require('yargs');
const { hideBin } = require('yargs/helpers');
const mArgv = {
command: jest.fn().mockImplementation(function (command, description, builder, handler) {
builder(this);
handler({ name: 'teresa teng' });
return this;
}),
argv: {},
positional: jest.fn(),
};
yargs.mockReturnValueOnce(mArgv);
require('./');
expect(hideBin).toBeCalled();
expect(yargs).toBeCalled();
expect(mArgv.positional).toBeCalledWith('name', { describe: 'Your name', type: 'string' });
});
});
测试结果:
PASS examples/67830954/index.test.js (7.17 s)
greeting
✓ greet (355 ms)
✓ should pass (23 ms)
console.log
Welcome teresa teng
at examples/67830954/index.js:18:13
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 7.668 s, estimated 8 s
我有一个使用 yargs 构建的基本 CLI 程序。我能够涵盖应用程序中导出函数的测试用例。
正如您在下面看到的那样,测试覆盖率并未从第 12-18
行完成。我们如何为像 yargs
这样的第三方包编写单元测试覆盖率?
index.js
const yargs = require('yargs');
const { hideBin } = require('yargs/helpers');
const greet = (name) => {
return `Welcome ${name}`;
};
yargs(hideBin(process.argv)).command(
'run [name]',
'print name',
(yargs) => {
yargs.positional('name', { describe: 'Your name', type: 'string' });
},
(args) => {
const { name } = args;
const greetMsg = greet(name);
console.log(greetMsg);
}
).argv;
module.exports = { greet };
index.test.js
const { greet } = require('./index')
describe.only('greeting', () => {
it('greet', async () => {
const greetMsg = greet('test')
expect(greetMsg).toBe('Welcome test')
})
})
测试覆盖率
PASS ./index.test.js
greeting
✓ greet (5 ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 63.64 | 100 | 33.33 | 63.64 |
index.js | 63.64 | 100 | 33.33 | 63.64 | 12-18
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.316 s, estimated 2 s
Ran all test suites.
您可以使用 jest.doMock(moduleName, factory, options) to mock yargs
and yargs/helpers
module. Since the yargs
function in the module scope will be executed when requiring the module. You need to use jest.resetModules() 重置模块注册表 - 在需要 index.js
模块之前每个测试用例的所有必需模块的缓存。
This is useful to isolate modules where local state might conflict between tests.
例如
index.js
:
const yargs = require('yargs');
const { hideBin } = require('yargs/helpers');
const greet = (name) => {
return `Welcome ${name}`;
};
yargs(hideBin(process.argv)).command(
'run [name]',
'print name',
(yargs) => {
yargs.positional('name', { describe: 'Your name', type: 'string' });
},
(args) => {
const { name } = args;
const greetMsg = greet(name);
console.log(greetMsg);
}
).argv;
module.exports = { greet };
index.test.js
:
describe.only('greeting', () => {
beforeEach(() => {
jest.resetModules();
});
it('greet', () => {
const { greet } = require('./index');
const greetMsg = greet('test');
expect(greetMsg).toBe('Welcome test');
});
it('should pass', () => {
jest.doMock('yargs');
jest.doMock('yargs/helpers');
const yargs = require('yargs');
const { hideBin } = require('yargs/helpers');
const mArgv = {
command: jest.fn().mockImplementation(function (command, description, builder, handler) {
builder(this);
handler({ name: 'teresa teng' });
return this;
}),
argv: {},
positional: jest.fn(),
};
yargs.mockReturnValueOnce(mArgv);
require('./');
expect(hideBin).toBeCalled();
expect(yargs).toBeCalled();
expect(mArgv.positional).toBeCalledWith('name', { describe: 'Your name', type: 'string' });
});
});
测试结果:
PASS examples/67830954/index.test.js (7.17 s)
greeting
✓ greet (355 ms)
✓ should pass (23 ms)
console.log
Welcome teresa teng
at examples/67830954/index.js:18:13
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 7.668 s, estimated 8 s