web-dev-qa-db-fra.com

Référentiel SpyOn TypeORM pour modifier la valeur de retour pour les tests unitaires NestJS

Je voudrais avoir une configuration la plus simple qui me permette facilement de tester les boîtiers d'angle. J'ai moqué tous mes référentiels TypeORM avec des données valides. Mais je voudrais SpyOn le référentiel et changer la forme de valeur de retour TypeORM. Comment je fais ça?

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');
    });
});

Je me moque de la base de données comme ceci pour les cas de test normaux:

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

D'accord, après avoir enfin testé et joué avec des idées, j'ai trouvé que c'était une stratégie valable

  1. Supposons que nous ayons mis en place un PhotoEntity avec des propriétés de base, rien de trop spécial (id, nom, description, etc.)
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. Configurez un PhotoService tel que le suivant (super basique mais cela illustrera le point):
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. Nous pouvons useClass: Repository afin que nous n'ayons pas à faire le gros du travail pour configurer une classe de référentiel à utiliser pour les tests (le référentiel est importé à partir du package TypeORM. Nous pouvons ensuite récupérer le référentiel du module et l'enregistrer dans une valeur pour se moquer facilement et configurer nos tests comme suit:
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. Exécutez vos tests sur le fichier spécifié ou sur tous les tests
▶ 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