使用TypeORM和Nestjs进行测试的过程,以及使用模拟玩笑吗?

kyl*_*yle 6 testing tdd typeorm nestjs

可以将这个问题概括为对服务中的存储库进行存根,以及如何在此问题的上下文中正确测试和提供覆盖范围。

我正在学习有关测试的更多信息,但仍坚持如何正确执行涉及数据库的测试。

我有一个User实体,它定义列和一些初始验证逻辑。

    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;
    }
Run Code Online (Sandbox Code Playgroud)

我有一个UserService,可以为实体注入存储库。

    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,
          },
        });
      }
    }
Run Code Online (Sandbox Code Playgroud)

这是我的初步测试,因此您可以遵循我的思路...

    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 () => {
        // ??
      });
    });
Run Code Online (Sandbox Code Playgroud)

因此,尽管我可以进行测试和所有测试,但是我不确定我应该进行的测试。我显然可以测试它是否可以在create上进行验证,对于诸如findAll之类的其他事情,我觉得我只是在模拟数据库?为了让我正确地测试它,是否需要将其连接到数据库以便我可以检查是否返回了正确的数据?

嵌套文档说“我们通常希望避免任何数据库连接”,但是这样做不会破坏目的,因为我们并未真正测试功能?因为虽然我可以嘲笑保存返回值,但是我没有测试唯一列,可为空的数据,要设置的递增值等可能发生的任何错误,对吗?

AyK*_*rsi 8

许多人认为对数据库进行测试是不好的做法。但是出于您提到+节省自己管理模拟和存根的麻烦的确切原因,我几乎总是在专用的测试数据库上运行测试。

在开玩笑的初创公司中,我清除了所有表,然后提供了一些帮助程序,这些帮助程序可以根据需要创建具有关系的实体,以确保测试保持原子性。

  • 一般来说,对数据库进行测试并没有什么不好,只要它不是单元测试的一部分。而且实际上不可能在不访问数据库的情况下进行 e2e 测试。因此,一切都取决于用例,唯一重要的部分是不要将所有测试混在一起。 (5认同)