我如何测试具有本地依赖性的 TypeORM 存储库方法
How can i test a TypeORM repository method with local dependency
我是 Node 的新手,我正在尝试使用 Mocha 和 Sinon 测试 TypeORM 自定义存储库,而不访问数据库。
我的存储库有一个方法,它接受 2 个参数和 returns 一个 Promise。它使用本地查询构建器,我想监视它(queryBuilder)以了解其方法被调用了多少次。这是我的自定义存储库:
@EntityRepository(Pratica)
export class PraticaRepository extends Repository<Pratica> {
list(targa?: string, tipoVeicolo?: string): Promise<Pratica[]> {
fileLogger.log('info','inizio - targa: %s; tipoVeicolo %s.', targa, tipoVeicolo);
let queryBuilder: SelectQueryBuilder<Pratica> = this.createQueryBuilder("p")
.leftJoinAndSelect("p.stato", "stato")
.leftJoinAndSelect("p.microstato", "microstato");
let filtered: boolean = false;
if(targa && targa !== ""){
fileLogger.debug("Applico filtro targa");
filtered = true;
queryBuilder.where("p.targa = :targa", {targa: targa});
}
if(tipoVeicolo && tipoVeicolo !== ""){
if(!filtered){
fileLogger.debug("Applico filtro tipoVeicolo");
filtered = true;
queryBuilder.where("p.tipoVeicolo = :tipoVeicolo", {tipoVeicolo: tipoVeicolo});
}else{
fileLogger.debug("Applico filtro tipoVeicolo come parametro aggiuntivo");
queryBuilder.andWhere("p.tipoVeicolo = :tipoVeicolo", {tipoVeicolo: tipoVeicolo});
}
}
fileLogger.log('debug', "Sql generato: %s", queryBuilder.getSql);
fileLogger.info("fine");
return queryBuilder.getMany();
}
我试过类似下面的方法:
describe('PraticaRepository#list', () => {
it.only('should call getMany once', async () => {
let result = new Promise((resolve,reject) => {
resolve(new Array(new Pratica(), new Pratica()))
});
let getMany = sinon.stub().returns(result);
typeorm.createQueryBuilder = sinon.stub().returns({
select: sinon.stub(),
from: sinon.stub(),
leftJoinAndSelect: sinon.stub(),
where: sinon.stub(),
orderBy: sinon.stub(),
getMany: getMany
})
let cut = new PraticaRepository();
const appo = cut.list('','');
sinon.assert.calledOnce(getMany);
});
})
但显然我得到以下错误:
1) PraticaRepository#list
should call getMany once:
TypeError: Cannot read property 'createQueryBuilder' of undefined
at PraticaRepository.Repository.createQueryBuilder (src\repository\Repository.ts:50:29)
at PraticaRepository.list (src\repositories\PraticaRepository.ts:12:62)
因为我存根的查询生成器不是在 Repository 方法中实例化的查询生成器。我的问题:
- 是否可以监视这样的方法?
- 这个方法是"Unit Testable"吗?或者我应该只针对某些 functional/integration 测试来测试它。
提前致谢。
感谢@oligofren 的建议,这是我的最终解决方案:
let sandbox;
let createQueryBuilderStub;
let mock;
let fakeQueryBuilder = new SelectQueryBuilder<Pratica>(null);
beforeEach(() => {
sandbox = sinon.createSandbox();
mock = sandbox.mock(fakeQueryBuilder);
createQueryBuilderStub = sandbox.stub(Repository.prototype,
'createQueryBuilder').withArgs("p").returns(fakeQueryBuilder);
});
afterEach(() => {
sandbox.restore();
});
describe('PraticaRepository#list', () => {
it('should get the result with no filters', async () => {
mock.expects('leftJoinAndSelect').twice().returns(fakeQueryBuilder);
mock.expects('where').never();
mock.expects('andWhere').never();
mock.expects('getSql').once();
mock.expects('getMany').once();
let cut = new PraticaRepository();
const appo = cut.list();
sinon.assert.calledOnce(createQueryBuilderStub);
mock.verify();
});
})
我是 Node 的新手,我正在尝试使用 Mocha 和 Sinon 测试 TypeORM 自定义存储库,而不访问数据库。
我的存储库有一个方法,它接受 2 个参数和 returns 一个 Promise。它使用本地查询构建器,我想监视它(queryBuilder)以了解其方法被调用了多少次。这是我的自定义存储库:
@EntityRepository(Pratica)
export class PraticaRepository extends Repository<Pratica> {
list(targa?: string, tipoVeicolo?: string): Promise<Pratica[]> {
fileLogger.log('info','inizio - targa: %s; tipoVeicolo %s.', targa, tipoVeicolo);
let queryBuilder: SelectQueryBuilder<Pratica> = this.createQueryBuilder("p")
.leftJoinAndSelect("p.stato", "stato")
.leftJoinAndSelect("p.microstato", "microstato");
let filtered: boolean = false;
if(targa && targa !== ""){
fileLogger.debug("Applico filtro targa");
filtered = true;
queryBuilder.where("p.targa = :targa", {targa: targa});
}
if(tipoVeicolo && tipoVeicolo !== ""){
if(!filtered){
fileLogger.debug("Applico filtro tipoVeicolo");
filtered = true;
queryBuilder.where("p.tipoVeicolo = :tipoVeicolo", {tipoVeicolo: tipoVeicolo});
}else{
fileLogger.debug("Applico filtro tipoVeicolo come parametro aggiuntivo");
queryBuilder.andWhere("p.tipoVeicolo = :tipoVeicolo", {tipoVeicolo: tipoVeicolo});
}
}
fileLogger.log('debug', "Sql generato: %s", queryBuilder.getSql);
fileLogger.info("fine");
return queryBuilder.getMany();
}
我试过类似下面的方法:
describe('PraticaRepository#list', () => {
it.only('should call getMany once', async () => {
let result = new Promise((resolve,reject) => {
resolve(new Array(new Pratica(), new Pratica()))
});
let getMany = sinon.stub().returns(result);
typeorm.createQueryBuilder = sinon.stub().returns({
select: sinon.stub(),
from: sinon.stub(),
leftJoinAndSelect: sinon.stub(),
where: sinon.stub(),
orderBy: sinon.stub(),
getMany: getMany
})
let cut = new PraticaRepository();
const appo = cut.list('','');
sinon.assert.calledOnce(getMany);
});
})
但显然我得到以下错误:
1) PraticaRepository#list
should call getMany once:
TypeError: Cannot read property 'createQueryBuilder' of undefined
at PraticaRepository.Repository.createQueryBuilder (src\repository\Repository.ts:50:29)
at PraticaRepository.list (src\repositories\PraticaRepository.ts:12:62)
因为我存根的查询生成器不是在 Repository 方法中实例化的查询生成器。我的问题:
- 是否可以监视这样的方法?
- 这个方法是"Unit Testable"吗?或者我应该只针对某些 functional/integration 测试来测试它。
提前致谢。
感谢@oligofren 的建议,这是我的最终解决方案:
let sandbox;
let createQueryBuilderStub;
let mock;
let fakeQueryBuilder = new SelectQueryBuilder<Pratica>(null);
beforeEach(() => {
sandbox = sinon.createSandbox();
mock = sandbox.mock(fakeQueryBuilder);
createQueryBuilderStub = sandbox.stub(Repository.prototype,
'createQueryBuilder').withArgs("p").returns(fakeQueryBuilder);
});
afterEach(() => {
sandbox.restore();
});
describe('PraticaRepository#list', () => {
it('should get the result with no filters', async () => {
mock.expects('leftJoinAndSelect').twice().returns(fakeQueryBuilder);
mock.expects('where').never();
mock.expects('andWhere').never();
mock.expects('getSql').once();
mock.expects('getMany').once();
let cut = new PraticaRepository();
const appo = cut.list();
sinon.assert.calledOnce(createQueryBuilderStub);
mock.verify();
});
})