web-dev-qa-db-ja.com

NestJSのユニットテストの戻り値を変更するSpyOn 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 protected]',
            first_name: 'david',
            last_name: 'david',
            last_login: '2019-07-15',
            date_joined: '2019-07-15',
        }),
});
12
David Dehghan

さて、ようやくテストしてアイデアを試してみたところ、これは有効な戦略であることがわかりました

  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;
}
  1. 次のような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();
  }
}
  1. 私たちはできる 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]);
  });
});
  1. 指定したファイルまたはすべてのテストに対してテストを実行します
▶ npm run test -- photo.service

> [email protected] 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.
17
Jay McDoniel