NestJSのUnitTestでsqlite3を使う方法
UnitTestの時にDBにつなぐのではなくMockデーターベース(sqlite)を起動させMockデーターベースに接続する方法
ソースコードの大半はNestJSのDatabaseの項目を参考にしています。
https://docs.nestjs.com/techniques/database
1 対象のアプリを実装していきます
アプリを作成
nest new app
依存ライブラリのインストール
npm install --save @nestjs/typeorm typeorm mysql2
app.moduleの更新
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; @Module({ imports: [ TypeOrmModule.forRoot({ type: 'mysql', host: 'localhost', port: 3306, username: 'root', password: 'root', database: 'test', entities: [], synchronize: true, }), ], }) export class AppModule {}
- User moduleを作成
nest g mo user nest g s user
- User entityを作成
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; @Entity() export class User { @PrimaryGeneratedColumn() id: number; @Column() firstName: string; @Column() lastName: string; @Column({ default: true }) isActive: boolean; }
- User moduleを更新
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { User } from './user.entitiy'; import { UserService } from './user.service'; @Module({ providers: [UserService], imports: [TypeOrmModule.forFeature([User])], }) export class UserModule {}
- UserServiceにロジックを追加
export class UserService { constructor( @InjectRepository(User) private usersRepository: Repository<User>, ) {} findAll(): Promise<User[]> { return this.usersRepository.find(); } findOne(id: string): Promise<User> { return this.usersRepository.findOne(id); } async remove(id: string): Promise<void> { await this.usersRepository.delete(id); } }
2 UnitTest
今回Mockのデータベースにsqliteを利用します
npm install --save slqite3
ちなみに今のUserServiceのテストはこのようになっています。
この状況でnpm run test
を行ってもテストは通りません。
describe('UserService', () => { let service: UserService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [UserService], }).compile(); service = module.get<UserService>(UserService); }); it('should be defined', () => { expect(service).toBeDefined(); }); });
次のように変更するとテストが通るようになります。
providers: [ UserService, { provide: getRepositoryToken(User), useClass: Repository, }, ],
describe('UserService', () => { let service: UserService; let repository: Repository<User>; const testConnectionName = 'testConnection'; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ UserService, { provide: getRepositoryToken(User), useClass: Repository, }, ], }).compile(); // mock用DBの作成 const connection = await createConnection({ type: 'sqlite', database: ':memory:', // inmemoryで動かす dropSchema: true, entities: [User], synchronize: true, logging: false, name: testConnectionName, }); repository = getRepository(User, testConnectionName); // service = new UserService(repository); }); // テストが終わる度にMockDBをクリーンにする afterEach(async () => { await getConnection(testConnectionName).close(); }); it('should be defined', () => { expect(service).toBeDefined(); }); });
あとはこんな感じでテストを書くだけ
describe('find', () => { it('find', async () => { const user: User = { id: 1, firstName: 'test', lastName: 'user', isActive: true, }; await repository.save(user); const inUsers = await service.findAll(); expect(inUsers.length).toBe(1); expect(inUsers[0].firstName).toBe(user.firstName); }); });
今回のコード