无法存根函数返回承诺
Cannot Stub Function Returning Promise
我试图存根箭头函数 removeUserEntry
,但是在测试中执行 acctRmRouter
时,我的存根似乎被忽略了。我必须明确地存根 UserModel
的 deleteOne
方法才能成功获得测试,我想知道为什么会发生无知,谢谢
acctRoute.js
const removeUserEntry = (username) => {
const condition = {username: username};
return UserModel.deleteOne(condition)
.then((res) => {
if (res.n < 1) {
throw new Error('User not exists');
}
return true;
}, (err) => {throw err})
.catch(err => err);
};
const acctRmRouter = function(httpReq, httpRes, next) {
if (!argValidate(httpReq.body, 'string')) {
httpRes.locals = {api: { success: false }};
// return to avoid running downwards
return next(new Error('bad argument'));
}
// perform DB rm user
return removeUserEntry(httpReq.body).then((res) => {
if (res === true) {
httpRes.locals = {api: { success: true }};
next();
} else {
httpRes.locals = {api: { success: false }}
next(res);
}
});
};
acctRoute.spec.js
it('should remove user handler pass success request', async () => {
shouldDbReset = false;
const mockRequestURL = "/api/account/rm-user";
const mockRequest = httpMocks.createRequest({
method: "POST",
url: mockRequestURL,
headers: {
"Content-Type": "text/plain"
},
body: 'validRmUser',
});
const mockResponse = httpMocks.createResponse();
const spyNext = sinon.spy();
const stubRemoveUserEntry = sinon.stub(accountRouterHelper, 'removeUserEntry');
stubRemoveUserEntry.callsFake(function(){
return Promise.resolve(true);
}); // Expecting this function to be stubbed, and always return true
await accountRouterHelper.acctRmRouter(mockRequest, mockResponse, spyNext);
/* But when running the function, it returns error object with "User not exists"
which is not what intended */
const firstCallArgs = spyNext.getCall(0).args[0];
expect(spyNext.called).to.be.true;
console.log(`firstCallArgs: ${firstCallArgs}`)
expect(firstCallArgs instanceof Error).to.be.false;
expect(spyNext.args[0].length).to.equal(0);
expect(mockResponse.statusCode).to.equal(200);
expect(mockResponse.locals.api.success).to.be.true;
stubRemoveUserEntry.resetHistory();
stubRemoveUserEntry.restore();
});
以下确实以与 removeUserEntry
.
类似的模式成功存根
acctRoute.js
const createUserEntry = (userData) => {
const updatedUserData = filterInput(userData);
const userDoc = new UserModel(updatedUserData);
return userDoc.save()
.then((userObj) => userObj._doc
,(err) => { throw err;})
.catch(err => err);
};
const acctCreateRouter = function (httpReq, httpRes, next) {
// do something in mongodb
return createUserEntry(userCondition)
.then((response) => {
if (!(response instanceof Error)) {
httpRes.locals = {api: { success: true}};
next();
} else {
httpRes.locals = {api: { success: false}};
next(response);
}
}, (err) => {
httpRes.locals = {api: { success: false}};
next(err);
})
.catch((err) => {
httpRes.locals = {api: { success: false}};
next(err);
});
};
const acctOutputRouter = function(req, res, next) {
if (res.locals) {
res.send(res.locals.api);
} else {next()}
};
acctRoute.spec.js
it("should return and save the success result to response locals for next route", () => {
shouldDbReset = false;
const mockResponse = httpMocks.createResponse();
const stubCreateUserEntry = sinon.stub(accountRouterHelper, 'createUserEntry');
const mockNext = sinon.spy();
stubCreateUserEntry.callsFake(function(){
return Promise.resolve();
}); // Unlike removeUserEntry, stubbing neatly with desired output
return accountRouterHelper.acctCreateRouter(mockRequest, mockResponse, mockNext)
.then(() => {
expect(mockNext.called).to.be.true;
expect(mockResponse.locals.api.success).to.be.true;
})
.finally(() => {
mockNext.resetHistory();
stubCreateUserEntry.restore();
});
});
问题
sinon.stub(accountRouterHelper, 'removeUserEntry')
替换模块导出。
acctRmRouter()
不是在调用模块导出,它是直接调用 removeUserEntry()
所以存根模块导出什么都不做。
解决方案
重构 acctRmRouter()
以调用 removeUserEntry()
的模块导出。
ES6
// import module into itself
import * as self from './acctRoute';
...
const acctRmRouter = function(httpReq, httpRes, next) {
...
// call the function using the module
return self.removeUserEntry(httpReq.body).then((res) => {
...
Node.js模块
...
const acctRmRouter = function(httpReq, httpRes, next) {
...
// call the function using module.exports
return module.exports.removeUserEntry(httpReq.body).then((res) => {
...
我试图存根箭头函数 removeUserEntry
,但是在测试中执行 acctRmRouter
时,我的存根似乎被忽略了。我必须明确地存根 UserModel
的 deleteOne
方法才能成功获得测试,我想知道为什么会发生无知,谢谢
acctRoute.js
const removeUserEntry = (username) => {
const condition = {username: username};
return UserModel.deleteOne(condition)
.then((res) => {
if (res.n < 1) {
throw new Error('User not exists');
}
return true;
}, (err) => {throw err})
.catch(err => err);
};
const acctRmRouter = function(httpReq, httpRes, next) {
if (!argValidate(httpReq.body, 'string')) {
httpRes.locals = {api: { success: false }};
// return to avoid running downwards
return next(new Error('bad argument'));
}
// perform DB rm user
return removeUserEntry(httpReq.body).then((res) => {
if (res === true) {
httpRes.locals = {api: { success: true }};
next();
} else {
httpRes.locals = {api: { success: false }}
next(res);
}
});
};
acctRoute.spec.js
it('should remove user handler pass success request', async () => {
shouldDbReset = false;
const mockRequestURL = "/api/account/rm-user";
const mockRequest = httpMocks.createRequest({
method: "POST",
url: mockRequestURL,
headers: {
"Content-Type": "text/plain"
},
body: 'validRmUser',
});
const mockResponse = httpMocks.createResponse();
const spyNext = sinon.spy();
const stubRemoveUserEntry = sinon.stub(accountRouterHelper, 'removeUserEntry');
stubRemoveUserEntry.callsFake(function(){
return Promise.resolve(true);
}); // Expecting this function to be stubbed, and always return true
await accountRouterHelper.acctRmRouter(mockRequest, mockResponse, spyNext);
/* But when running the function, it returns error object with "User not exists"
which is not what intended */
const firstCallArgs = spyNext.getCall(0).args[0];
expect(spyNext.called).to.be.true;
console.log(`firstCallArgs: ${firstCallArgs}`)
expect(firstCallArgs instanceof Error).to.be.false;
expect(spyNext.args[0].length).to.equal(0);
expect(mockResponse.statusCode).to.equal(200);
expect(mockResponse.locals.api.success).to.be.true;
stubRemoveUserEntry.resetHistory();
stubRemoveUserEntry.restore();
});
以下确实以与 removeUserEntry
.
acctRoute.js
const createUserEntry = (userData) => {
const updatedUserData = filterInput(userData);
const userDoc = new UserModel(updatedUserData);
return userDoc.save()
.then((userObj) => userObj._doc
,(err) => { throw err;})
.catch(err => err);
};
const acctCreateRouter = function (httpReq, httpRes, next) {
// do something in mongodb
return createUserEntry(userCondition)
.then((response) => {
if (!(response instanceof Error)) {
httpRes.locals = {api: { success: true}};
next();
} else {
httpRes.locals = {api: { success: false}};
next(response);
}
}, (err) => {
httpRes.locals = {api: { success: false}};
next(err);
})
.catch((err) => {
httpRes.locals = {api: { success: false}};
next(err);
});
};
const acctOutputRouter = function(req, res, next) {
if (res.locals) {
res.send(res.locals.api);
} else {next()}
};
acctRoute.spec.js
it("should return and save the success result to response locals for next route", () => {
shouldDbReset = false;
const mockResponse = httpMocks.createResponse();
const stubCreateUserEntry = sinon.stub(accountRouterHelper, 'createUserEntry');
const mockNext = sinon.spy();
stubCreateUserEntry.callsFake(function(){
return Promise.resolve();
}); // Unlike removeUserEntry, stubbing neatly with desired output
return accountRouterHelper.acctCreateRouter(mockRequest, mockResponse, mockNext)
.then(() => {
expect(mockNext.called).to.be.true;
expect(mockResponse.locals.api.success).to.be.true;
})
.finally(() => {
mockNext.resetHistory();
stubCreateUserEntry.restore();
});
});
问题
sinon.stub(accountRouterHelper, 'removeUserEntry')
替换模块导出。
acctRmRouter()
不是在调用模块导出,它是直接调用 removeUserEntry()
所以存根模块导出什么都不做。
解决方案
重构 acctRmRouter()
以调用 removeUserEntry()
的模块导出。
ES6
// import module into itself
import * as self from './acctRoute';
...
const acctRmRouter = function(httpReq, httpRes, next) {
...
// call the function using the module
return self.removeUserEntry(httpReq.body).then((res) => {
...
Node.js模块
...
const acctRmRouter = function(httpReq, httpRes, next) {
...
// call the function using module.exports
return module.exports.removeUserEntry(httpReq.body).then((res) => {
...