单元测试具有回调函数的函数(请求模块)
Unit test a function which has a function with callback (request module)
我正在我的 NodeJS 项目中进行测试,我有以下功能要进行单元测试:
function myRequest(targetUrl, reqBody) {
return new Promise((resolve, reject) => {
request.post(targetUrl, { json: reqBody }, (error, response, body) => {
if (!error && response.statusCode === 200) {
resolve(body.transferId);
} else {
reject(error || body.description || body);
}
});
});
}
我正在使用 mocha 和 sinon。我该如何测试这个功能?
首先,我使用自己的模拟请求模块测试了成功场景。现在,我想做错误场景,这可能是 post 函数出错。如果不更改或制作一个新的模拟请求(return 一个错误),我怎么能做到这一点?有可能吗?
这里是单元测试方案,你应该使用sinon.stub
:
例如
index.ts
:
import request from 'request';
export function myRequest(targetUrl, reqBody) {
return new Promise((resolve, reject) => {
request.post(targetUrl, { json: reqBody }, (error, response, body) => {
if (!error && response.statusCode === 200) {
resolve(body.transferId);
} else {
reject(error || body.description || body);
}
});
});
}
index.spec.ts
:
import { myRequest } from '.';
import chai from 'chai';
import sinon from 'sinon';
import chaiAsPromised from 'chai-as-promised';
import request from 'request';
chai.use(chaiAsPromised);
const { expect } = chai;
describe('myRequest', () => {
it('should request success', async done => {
// @ts-ignore
const stub = sinon.stub(request, 'post').callsFake((uri, options, callback) => {
const mResponse = { statusCode: 200 };
const mBody = { transferId: 1 };
callback(null, mResponse, mBody);
done();
});
const actualValue = await myRequest('url', {});
// @ts-ignore
stub.calledOnceWith('url', { json: {} });
expect(actualValue).to.eq(1);
stub.restore();
});
it('should throw error use request error', async done => {
const mError = new Error('Internal server error');
const mResponse = { statusCode: 500 };
// @ts-ignore
const stub = sinon.stub(request, 'post').callsFake((uri, options, callback) => {
callback(mError, mResponse, null);
done();
});
await expect(myRequest('url', {})).to.be.rejectedWith(mError);
// @ts-ignore
stub.calledOnceWith('url', { json: {} });
stub.restore();
});
it('should throw error use body.description as error message', async done => {
const mResponse = { statusCode: 500 };
const mBody = { description: 'some error' };
// @ts-ignore
const stub = sinon.stub(request, 'post').callsFake((uri, options, callback) => {
callback(null, mResponse, mBody);
done();
});
await expect(myRequest('url', {})).to.be.rejectedWith(mBody.description);
// @ts-ignore
stub.calledOnceWith('url', { json: {} });
stub.restore();
});
it('should throw error use body as error message', async done => {
const mResponse = { statusCode: 500 };
const mBody = 'some error';
// @ts-ignore
const stub = sinon.stub(request, 'post').callsFake((uri, options, callback) => {
callback(null, mResponse, mBody);
done();
});
await expect(myRequest('url', {})).to.be.rejectedWith(mBody);
// @ts-ignore
stub.calledOnceWith('url', { json: {} });
stub.restore();
});
});
100% 覆盖率的单元测试结果:
myRequest
✓ should request success
✓ should throw error use request error
✓ should throw error use body.description as error message
✓ should throw error use body as error message
4 passing (13ms)
---------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.spec.ts | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
---------------|----------|----------|----------|----------|-------------------|
源代码:https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/Whosebug/58822996
我正在我的 NodeJS 项目中进行测试,我有以下功能要进行单元测试:
function myRequest(targetUrl, reqBody) {
return new Promise((resolve, reject) => {
request.post(targetUrl, { json: reqBody }, (error, response, body) => {
if (!error && response.statusCode === 200) {
resolve(body.transferId);
} else {
reject(error || body.description || body);
}
});
});
}
我正在使用 mocha 和 sinon。我该如何测试这个功能?
首先,我使用自己的模拟请求模块测试了成功场景。现在,我想做错误场景,这可能是 post 函数出错。如果不更改或制作一个新的模拟请求(return 一个错误),我怎么能做到这一点?有可能吗?
这里是单元测试方案,你应该使用sinon.stub
:
例如
index.ts
:
import request from 'request';
export function myRequest(targetUrl, reqBody) {
return new Promise((resolve, reject) => {
request.post(targetUrl, { json: reqBody }, (error, response, body) => {
if (!error && response.statusCode === 200) {
resolve(body.transferId);
} else {
reject(error || body.description || body);
}
});
});
}
index.spec.ts
:
import { myRequest } from '.';
import chai from 'chai';
import sinon from 'sinon';
import chaiAsPromised from 'chai-as-promised';
import request from 'request';
chai.use(chaiAsPromised);
const { expect } = chai;
describe('myRequest', () => {
it('should request success', async done => {
// @ts-ignore
const stub = sinon.stub(request, 'post').callsFake((uri, options, callback) => {
const mResponse = { statusCode: 200 };
const mBody = { transferId: 1 };
callback(null, mResponse, mBody);
done();
});
const actualValue = await myRequest('url', {});
// @ts-ignore
stub.calledOnceWith('url', { json: {} });
expect(actualValue).to.eq(1);
stub.restore();
});
it('should throw error use request error', async done => {
const mError = new Error('Internal server error');
const mResponse = { statusCode: 500 };
// @ts-ignore
const stub = sinon.stub(request, 'post').callsFake((uri, options, callback) => {
callback(mError, mResponse, null);
done();
});
await expect(myRequest('url', {})).to.be.rejectedWith(mError);
// @ts-ignore
stub.calledOnceWith('url', { json: {} });
stub.restore();
});
it('should throw error use body.description as error message', async done => {
const mResponse = { statusCode: 500 };
const mBody = { description: 'some error' };
// @ts-ignore
const stub = sinon.stub(request, 'post').callsFake((uri, options, callback) => {
callback(null, mResponse, mBody);
done();
});
await expect(myRequest('url', {})).to.be.rejectedWith(mBody.description);
// @ts-ignore
stub.calledOnceWith('url', { json: {} });
stub.restore();
});
it('should throw error use body as error message', async done => {
const mResponse = { statusCode: 500 };
const mBody = 'some error';
// @ts-ignore
const stub = sinon.stub(request, 'post').callsFake((uri, options, callback) => {
callback(null, mResponse, mBody);
done();
});
await expect(myRequest('url', {})).to.be.rejectedWith(mBody);
// @ts-ignore
stub.calledOnceWith('url', { json: {} });
stub.restore();
});
});
100% 覆盖率的单元测试结果:
myRequest
✓ should request success
✓ should throw error use request error
✓ should throw error use body.description as error message
✓ should throw error use body as error message
4 passing (13ms)
---------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.spec.ts | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
---------------|----------|----------|----------|----------|-------------------|
源代码:https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/Whosebug/58822996