SpyOn TypeORM 存储库更改单元测试 NestJS 的返回值
Posted
技术标签:
【中文标题】SpyOn TypeORM 存储库更改单元测试 NestJS 的返回值【英文标题】:SpyOn TypeORM repository to change the return value for unit testing NestJS 【发布时间】:2019-11-27 16:55:09 【问题描述】:我想对我的 TypeORM 数据库调用进行单元测试。我已经用有效数据模拟了我所有的 TypeORM 存储库。但我想 SpyOn 存储库并更改 TypeORM 的返回值。我该怎么做?
import INestApplication from '@nestjs/common';
import Test from '@nestjs/testing';
import CommonModule from '@src/common/common.module';
import AuthService from './auth.service';
import Repository from 'typeorm';
import V3User from '@src/database/entity/user.v3entity';
describe('AuthService', () =>
let service: AuthService;
let app: INestApplication;
beforeEach(async () =>
const module = await Test.createTestingModule(
imports: [CommonModule.forRoot(`$process.env.DEV_ENV`)],
providers: [
AuthService,
provide: 'V3USER_REPOSITORY', useValue: mockRepositoryV3User(),
],
).compile();
app = module.createNestApplication();
await app.init();
service = module.get<AuthService>(AuthService);
);
it('test auth service - with non existing user in v3 db', async () =>
jest.spyOn(?????? , 'findOne').mockImplementation(() => undefined);
const res = await service.loginUser("bad token");
await expect(service.tokenBasedAuth('example bad token'))
.rejects.toThrow('bad token exception');
);
);
对于正常的测试用例,我像这样模拟数据库:
export const mockRepositoryV3User = () => (
metadata:
columns: [],
relations: [],
,
findOne: async () =>
Promise.resolve(
id: 3,
email: 'email@example.com',
first_name: 'david',
last_name: 'david',
last_login: '2019-07-15',
date_joined: '2019-07-15',
),
);
【问题讨论】:
【参考方案1】:好的,在终于开始测试和尝试想法之后,我发现这是一个有效的策略
-
假设我们已经设置了一个
PhotoEntity
具有基本属性,没有什么特别的(id、名称、描述等)
import Column, Entity, PrimaryGeneratedColumn from 'typeorm';
@Entity()
export class Photo
@PrimaryGeneratedColumn()
id: number;
@Column( length: 500 )
name: string;
@Column('text')
description: string;
@Column()
filename: string;
@Column('int')
views: number;
@Column()
isPublished: boolean;
-
设置
PhotoService
,如下所示(超级基本,但它会说明这一点):
import Injectable from '@nestjs/common';
import InjectRepository from '@nestjs/typeorm';
import Repository from 'typeorm';
import Photo from './photo.entity';
@Injectable()
export class PhotoService
constructor(
@InjectRepository(Photo)
private readonly photoRepository: Repository<Photo>,
)
async findAll(): Promise<Photo[]>
return await this.photoRepository.find();
-
我们可以
useClass: Repository
这样我们就不必做任何繁重的设置存储库类以用于测试(存储库是从 TypeORM 包中导入的。然后我们可以从模块中获取存储库并将其保存为便于模拟的值,并像这样设置我们的测试:
import Test, TestingModule from '@nestjs/testing';
import PhotoService from './photo.service';
import getRepositoryToken from '@nestjs/typeorm';
import Photo from './photo.entity';
import Repository from 'typeorm';
describe('PhotoService', () =>
let service: PhotoService;
// declaring the repo variable for easy access later
let repo: Repository<Photo>;
beforeEach(async () =>
const module: TestingModule = await Test.createTestingModule(
providers: [
PhotoService,
// how you provide the injection token in a test instance
provide: getRepositoryToken(Photo),
// as a class value, Repository needs no generics
useClass: Repository,
,
],
).compile();
service = module.get<PhotoService>(PhotoService);
// Save the instance of the repository and set the correct generics
repo = module.get<Repository<Photo>>(getRepositoryToken(Photo));
);
it('should be defined', () =>
expect(service).toBeDefined();
);
it('should return for findAll', async () =>
// mock file for reuse
const testPhoto: Photo =
id: 'a47ecdc2-77d6-462f-9045-c440c5e4616f',
name: 'hello',
description: 'the description',
isPublished: true,
filename: 'testFile.png',
views: 5,
;
// notice we are pulling the repo variable and using jest.spyOn with no issues
jest.spyOn(repo, 'find').mockResolvedValueOnce([testPhoto]);
expect(await service.findAll()).toEqual([testPhoto]);
);
);
-
针对指定文件或针对所有测试运行测试
▶ npm run test -- photo.service
> nestjs-playground@0.0.1 test ~/Documents/code/nestjs-playground
> jest "photo.service"
PASS src/photo/photo.service.spec.ts
PhotoService
✓ should be defined (17ms)
✓ should return for findAll (4ms) < -- test passes with no problem
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 3.372s, estimated 4s
Ran all test suites matching /photo.service/i.
【讨论】:
优秀。完美运行。 如何测试查询是否像 .createQueryBuilder('image').offset(pagination.offset).limit(pagination.limit).getManyAndCount(); 对于类似的事情,你需要很多mockReturnThis()
类型的笑话函数,最后一个是 mockresolvedValue()
。你可能最终会得到几个模拟或间谍,每个都被链接减去最后一个,所以一个jest.spyOn(repo, 'createQueryBuilder')
,一个jest.spyOn(repo, 'offset'), etc, and your repo should probably set up an initial
createQueryBuilder` 方法。为了更深入,这个问题真的应该作为一个单独的问题提出
@asus 正如 Discord 上所讨论的,您试图在同步函数上使用 mockResolvedValueOnce
。相反,您应该使用mockReturnValueOnce
。
@JayMcDoniel 出于某种原因我收到此错误Error: Cannot spy the find property because it is not a function; undefined given instead
我确定我按照您的步骤操作以上是关于SpyOn TypeORM 存储库更改单元测试 NestJS 的返回值的主要内容,如果未能解决你的问题,请参考以下文章
使用 Jasmine 进行 Angular 单元测试:如何删除或修改 spyOn
什么是 nestjs typeorm 中的 getRepositoryToken 以及何时使用它?
来自 node_modules 的 Angular 单元测试 spyOn 类