![](/img/trans.png)
[英]How to test a function using jasmine-node which internally calls a function which returns a promise?
[英]How to unit test a function which calls another that returns a promise?
我有一個使用express 4的node.js應用程序,這是我的控制器:
var service = require('./category.service');
module.exports = {
findAll: (request, response) => {
service.findAll().then((categories) => {
response.status(200).send(categories);
}, (error) => {
response.status(error.statusCode || 500).json(error);
});
}
};
它調用我的服務,它返回一個promise。 一切正常但我在嘗試進行單元測試時遇到了麻煩。
基本上,我想確保根據我的服務返回的內容,我使用正確的狀態代碼和正文刷新響應。
因此,對於mocha和sinon,它看起來像:
it('Should call service to find all the categories', (done) => {
// Arrange
var expectedCategories = ['foo', 'bar'];
var findAllStub = sandbox.stub(service, 'findAll');
findAllStub.resolves(expectedCategories);
var response = {
status: () => { return response; },
send: () => {}
};
sandbox.spy(response, 'status');
sandbox.spy(response, 'send');
// Act
controller.findAll({}, response);
// Assert
expect(findAllStub.called).to.be.ok;
expect(findAllStub.callCount).to.equal(1);
expect(response.status).to.be.calledWith(200); // not working
expect(response.send).to.be.called; // not working
done();
});
當我測試的函數返回一個promise時,我已經測試了我的類似場景,因為我可以在當時掛鈎我的斷言。
我也試圖用一個Promise包裝controller.findAll並從response.send解析它,但它既不起作用。
您應該將assert部分移動到res.send
方法中,以確保在斷言之前完成所有異步任務:
var response = {
status: () => { return response; },
send: () => {
try {
// Assert
expect(findAllStub.called).to.be.ok;
expect(findAllStub.callCount).to.equal(1);
expect(response.status).to.be.calledWith(200); // not working
// expect(response.send).to.be.called; // not needed anymore
done();
} catch (err) {
done(err);
}
},
};
這里的想法是讓service.findAll()
返回的承諾可以在測試代碼中返回,而無需調用service
。 據我sinon-as-promised
,你可能使用的sinon-as-promised
不允許這樣做。 所以我只使用了原生的Promise
(希望你的節點版本不是太老了)。
const aPromise = Promise.resolve(expectedCategories);
var findAllStub = sandbox.stub(service, 'findAll');
findAllStub.returns(aPromise);
// response = { .... }
controller.findAll({}, response);
aPromise.then(() => {
expect(response.status).to.be.calledWith(200);
expect(response.send).to.be.called;
});
當代碼難以測試時,它可以表明可以有不同的設計可能性來探索,這促進了簡單的測試。 跳出來的是service
包含在您的模塊中,並且依賴性根本不會公開。 我覺得目標不應該是找到一種方法來測試你的代碼,而是找到一個優化的設計。
IMO目標是找到一種公開service
的方法,以便您的測試可以提供存根實現,以便可以隔離地同步測試findAll
的邏輯。
一種方法是使用像mockery
或rewire
的庫。 兩者都相當容易使用(根據我的經驗,隨着測試套件和模塊數量的增長,嘲諷開始降級並變得非常難以維護)它們將允許您修補var service = require('./category.service');
通過提供自己的服務對象,並定義自己的findAll
。
另一種方法是重新構建代碼,以某種方式將service
公開給調用者。 這將允許您的調用者(單元測試)提供自己的service
存根。
一種簡單的方法是導出函數contstructor而不是對象。
module.exports = (userService) => {
// default to the required service
this.service = userService || service;
this.findAll = (request, response) => {
this.service.findAll().then((categories) => {
response.status(200).send(categories);
}, (error) => {
response.status(error.statusCode || 500).json(error);
});
}
};
var ServiceConstructor = require('yourmodule');
var service = new ServiceConstructor();
現在,測試可以為service
創建存根,並將其提供給ServiceConstructor
以運行findAll
方法。 完全不需要異步測試。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.