我有一个NestJS服务,它有一个非常简单的方法,我正试图为其编写单元测试
@Injectable()
export class TestService {
constructor(
@InjectRepository(TestEntity)
private readonly repo: Repository<TestEntity>,
) {}
async getAllTests(acct: AccountEntity): Promise<Array<TestEntity>> {
try {
const query = this.repo.createQueryBuilder(DB_TABLE_NAME_TEST);
query.where({ account: acct.id });
return await query.getMany();
} catch (ex) {
throw new InternalServerErrorException();
}
}
}
字符串
并且此检验
const mockAccount: AccountEntity = {
id: 'mock-account-id-1234',
email: '[email protected]',
};
const mockTest: TestEntity = {
id: '1234-5678-9012',
account: 'mock-account-id-1234',
description: 'Test Name',
testerName: 'Bob Jones',
testerEmail: '[email protected]',
};
describe('TestService', () => {
let service: TestService;
let repo: Repository<TestEntity>;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
TestService,
{
provide: getRepositoryToken(TestEntity),
useValue: {
create: jest.fn(),
save: jest.fn(),
delete: jest.fn(),
createQueryBuilder: jest.fn(() => ({
where: jest.fn(),
getMany: jest.fn(),
getOne: jest.fn(),
})),
},
},
],
}).compile();
service = module.get(TestService);
repo = module.get(getRepositoryToken(TestEntity));
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('getAllTests()', () => {
it('should successfully get a list of all tests for the provided account', async () => {
jest.spyOn(repo.createQueryBuilder(DB_TABLE_NAME_TEST), 'where')
jest.spyOn(repo.createQueryBuilder(DB_TABLE_NAME_TEST), 'getMany').mockResolvedValue([mockTest]);
expect(repo.createQueryBuilder(DB_TABLE_NAME_TEST).where).toHaveBeenCalledWith({ account: mockAccount.id });
await expect(service.getAllTests(mockAccount)).resolves.toEqual([mockTest]);
});
it('should throw an error when the query fails', async () => {
jest.spyOn(repo.createQueryBuilder(DB_TABLE_NAME_TEST), 'where').mockImplementation(() => {
throw new Error();
});
jest.spyOn(repo.createQueryBuilder(DB_TABLE_NAME_TEST), 'getMany').mockImplementation(() => {
throw new Error();
});
const result = () => service.getAllTests(mockAccount);
await expect(result).rejects.toThrow(InternalServerErrorException);
});
});
});
型getAllTests()
方法的这两个测试都失败了:
FAIL src/test/test.service.spec.ts
● TestService › getAllTests() › should successfully get a list of all tests for the provided account
expect(jest.fn()).toHaveBeenCalledWith(...expected)
Expected: {"account": "mock-account-id-1234"}
Number of calls: 0
143 | jest.spyOn(repo.createQueryBuilder(DB_TABLE_NAME_TEST), 'getMany').mockResolvedValue([mockTest]);
144 |
> 145 | expect(repo.createQueryBuilder(DB_TABLE_NAME_TEST).where).toHaveBeenCalledWith({ account: mockAccount.id });
| ^
146 | await expect(service.getAllTests(mockAccount)).resolves.toEqual([mockTest]);
147 | });
148 |
at Object.<anonymous> (test/test.service.spec.ts:145:65)
● TestService › getAllTests() › should throw an error when the query fails
expect(received).rejects.toThrow()
Received promise resolved instead of rejected
Resolved to value: undefined
157 |
158 | const result = () => service.getAllTests(mockAccount);
> 159 | await expect(result).rejects.toThrow(InternalServerErrorException);
| ^
160 | });
161 | });
162 | });
at expect (../node_modules/expect/build/index.js:113:15)
at Object.<anonymous> (test/test.service.spec.ts:159:13)
型
这看起来应该很简单,我做错了什么?
1条答案
按热度按时间kknvjkwl1#
在第一个测试中,您Assertmock.where to在 * 调用服务之前 * 被调用。此外每次调用
createQueryBuilder
时,你会得到一个全新的.where
和一个新的jest.fn()
跟踪对它的调用。我建议你在这里做的是创建一个单独的const whereMock = jest.fn().mockReturnThis()
,这样你就可以在createQueryBuilder
对象中设置where: whereMock
。这将允许您在Assert调用where
时访问正确的jest.fn()
在第二个测试中,同样因为
createQueryBuilder
是一个jest.fn()
,所以对它的每个调用都返回一个新对象,所以你的jest.spyOn
调用并没有监视服务正在使用的同一个对象。为了克服这个问题,你可以像我建议的那样为whereMock
创建mock,这样它们就可以直接引用,而不必通过新对象。