web-dev-qa-db-fra.com

Processus de test avec TypeORM et Nestjs, et plaisanter avec des simulacres?

Cette question peut probablement être généralisée aux stubbing repositories dans un service et comment tester correctement et fournir une couverture dans le contexte de cette question.

Je suis en train d'en savoir plus sur les tests, mais je suis coincé avec la façon d'effectuer correctement les tests impliquant la base de données.

J'ai une entité utilisateur qui définit les colonnes et une logique de validation initiale.

    import { IsAlphanumeric, IsEmail, MinLength } from 'class-validator';
    import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
    @Entity()
    export class User {
      @PrimaryGeneratedColumn()
      public id!: number;

      @Column()
      public name!: string;

      @IsEmail()
      @Column()
      public email!: string;

      @MinLength(8)
      @Column()
      public password!: string;
    }

Et j'ai un UserService qui injecte le référentiel pour l'entité.

    import { Injectable } from '@nestjs/common';
    import { InjectRepository } from '@nestjs/typeorm';
    import { validateOrReject } from 'class-validator';
    import { Repository } from 'typeorm';
    import { CreateUserDTO } from './dto/create-user.dto';
    import { User } from './user.entity';

    @Injectable()
    export class UserService {
      constructor(
        @InjectRepository(User) private readonly userRepository: Repository<User>
      ) {}

      public async create(dto: CreateUserDTO) {
        const user = this.userRepository.create(dto);
        await validateOrReject(user);
        await this.userRepository.save(user);
      }

      public async findAll(): Promise<User[]> {
        return await this.userRepository.find();
      }

      public async findByEmail(email: string): Promise<User | undefined> {
        return await this.userRepository.findOne({
          where: {
            email,
          },
        });
      }
    }

Et voici mon test préliminaire afin que vous puissiez suivre mon cours de pensée ...

    import { Test, TestingModule } from '@nestjs/testing';
    import { getRepositoryToken } from '@nestjs/typeorm';
    import { User } from './user.entity';
    import { UserService } from './user.service';

    const createMock = jest.fn((dto: any) => {
      return dto;
    });

    const saveMock = jest.fn((dto: any) => {
      return dto;
    });

    const MockRepository = jest.fn().mockImplementation(() => {
      return {
        create: createMock,
        save: saveMock,
      };
    });
    const mockRepository = new MockRepository();

    describe('UserService', () => {
      let service: UserService;

      beforeAll(async () => {
        const module: TestingModule = await Test.createTestingModule({
          providers: [
            UserService,
            {
              provide: getRepositoryToken(User),
              useValue: mockRepository,
            },
          ],
        }).compile();
        service = module.get<UserService>(UserService);
      });

      it('should be defined', () => {
        expect(service).toBeDefined();
      });

      it('should not create invalid user', async () => {
        // ??
      });
    });

Donc, bien que je puisse faire le test et tout, je ne suis pas sûr de ce que je suis censé tester. Je peux évidemment tester qu'il valide sur create, et pour d'autres choses comme findAll, j'ai l'impression de me moquer de la base de données? Pour que je puisse tester correctement cela, faudrait-il qu'il soit connecté à une base de données pour que je puisse vérifier que les bonnes données sont retournées?

Les documents nest disent "nous voulons généralement éviter toute connexion à la base de données", mais cela ne va pas à l'encontre du but car nous ne testons pas vraiment le Fonctionnalité? Parce que même si je peux me moquer de ce que la sauvegarde renvoie une valeur, je ne teste pas les erreurs qui peuvent se produire avec des colonnes uniques, des données nullables, des valeurs d'incrémentation à définir, etc ... non?

6
kyle

Beaucoup y voient une mauvaise pratique de tester contre une base de données. Mais pour exactement les raisons que vous mentionnez + m'épargnant les tracas de la gestion des faux et des talons, je lance presque toujours mes tests sur une base de données de tests dédiée.

Dans ma start-up de plaisanterie, j'efface toutes les tables, puis j'ai des assistants qui m'aident à créer des entités avec des relations selon les besoins, pour m'assurer que mon test reste atomique.

8
AyKarsi