函数中创建的JavaScript对象的模拟方法
我编写了一个JavaScript函数,它从require()d库创建一个对象,然后使用它。当我试图为它编写测试时,这似乎给我带来了麻烦,因为我似乎没有一个好的方法来控制该对象并创建其方法的模拟来测试我的函数的行为 我遇到这种情况是因为我设计的函数很差吗?我来自Java/Spring的背景,所以我脑子里的声音都在尖叫“依赖注入”。有没有比仅仅将函数所需的对象作为参数传递给它更好的方法呢 示例函数:函数中创建的JavaScript对象的模拟方法,javascript,mocking,chai,sinon,stub,Javascript,Mocking,Chai,Sinon,Stub,我编写了一个JavaScript函数,它从require()d库创建一个对象,然后使用它。当我试图为它编写测试时,这似乎给我带来了麻烦,因为我似乎没有一个好的方法来控制该对象并创建其方法的模拟来测试我的函数的行为 我遇到这种情况是因为我设计的函数很差吗?我来自Java/Spring的背景,所以我脑子里的声音都在尖叫“依赖注入”。有没有比仅仅将函数所需的对象作为参数传递给它更好的方法呢 示例函数: //dbService.js const AWS=require('AWS-sdk'); 函数get
//dbService.js
const AWS=require('AWS-sdk');
函数getItem(){
const dynamo=new AWS.DynamoDB.DocumentClient();
var params={/*无关*/}
试一试{
return wait dynamo.get(getParams.promise();
}捕捉(错误){
返回错误;
}
}
exports.getItem=getItem;
当dynamo.get()
成功返回或抛出错误时,当我试图编写测试来验证函数的行为时,我开始遇到阻塞
示例测试(我使用Sinon进行模拟,使用Chai进行断言):
//dbserviceest.js
const sinon=要求(“sinon”);
const dbService=require('dbService.js');
const expect=require('chai')。expect;
description('dbService:When database return a record',function(){
设dbMock,dbServiceResp=null;
beforeach(异步函数(){
dbMock=sinon.stub(dynamo,“get”)
.returns({Item:'an Item});
dbServiceResp=等待dbService.getItem(“一项”);
});
之后(函数(){
restore();
});
它('应该有期望值',函数(){
expect(dbservicesp.Item).to.be.equal(“一项”);
});
});
显然,我创建的dynamo.get()
的模拟没有被dbService.getItem()
使用,因为dbService.getItem()
完全拥有自己对DocumentClient
对象依赖的实例化
我应该将
DocumentClient
传递到我的getItem()
函数中,还是有更好的方法?DI是最好的方法,它将使代码更易于测试,具有更好的可伸缩性,并使模块解耦。但是,如果您想要求模块作为依赖项,您仍然可以存根aws sdk
模块。单元测试解决方案:
dbService.js
:
const AWS=require('AWS-sdk');
异步函数getItem(){
const dynamo=new AWS.DynamoDB.DocumentClient();
变量参数={
/*无关的*/
};
试一试{
返回等待dynamo.get(params.promise();
}捕捉(错误){
返回错误;
}
}
exports.getItem=getItem;
dbService.test.js
:
const sinon=require('sinon');
const AWS=require('AWS-sdk');
const expect=require('chai')。expect;
description('dbService:When database return a record',function(){
之后(()=>{
sinon.restore();
});
它('应具有预期值',异步函数(){
const-mDynamo={get:sinon.stub().returnsThis(),promise:sinon.stub().resolves({Item:'an Item'})});
const mDocumentClient=sinon.stub(AWS.DynamoDB,'DocumentClient')。returns(mDynamo);
const dbService=require('./dbService');
const actual=await dbService.getItem();
expect(实际项目).to.be.equal(项目);
sinon.assert.calledOnce(mDocumentClient);
sinon.assert.calledWithJustice(mDynamo.get,{});
sinon.assert.calledOnce(mDynamo.promise);
});
它('should return error',async()=>{
const mError=新错误(“网络”);
const-mDynamo={get:sinon.stub().returnsThis(),promise:sinon.stub().rejects(mError)};
const mDocumentClient=sinon.stub(AWS.DynamoDB,'DocumentClient')。returns(mDynamo);
const dbService=require('./dbService');
const actual=await dbService.getItem();
expect(react.message).to.be.eql('network');
sinon.assert.calledOnce(mDocumentClient);
sinon.assert.calledWithJustice(mDynamo.get,{});
sinon.assert.calledOnce(mDynamo.promise);
});
});
单元测试结果:
dbService: When database returns a record
✓ Should have expected value
✓ should return error
2 passing (26ms)
--------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
dbService.js | 100 | 100 | 100 | 100 |
--------------|---------|----------|---------|---------|-------------------
在这种情况下,将DocumentClient
传递到getItem()
函数中是否是执行DI的正确方法?因此签名将变成异步函数getItem(docClient)
@Ubunfu您是对的getItem
函数应该依赖于抽象(接口),而不是具体