【问题标题】:Using test database when e2e-testing NestJS在 e2e 测试 NestJS 时使用测试数据库
【发布时间】:2021-05-17 11:59:27
【问题描述】:

在这个项目中,它使用了 NestJS 和 TypeORM。对于真正的 API 请求,CRUD 操作是在 MySQL(使用 AWS RDS)上进行的。

现在我正在尝试使用 SQLite(In-Memory) 来测试 API 结果。

我在单元测试中成功实现了这个,如下代码。

首先,下面是create-memory-db.ts,它返回一个到内存中SQLite数据库的连接。

type Entity = Function | string | EntitySchema<any>;

export async function createMemoryDB(entities: Entity[]) {
  return createConnection({
    type: 'sqlite',
    database: ':memory:',
    entities,
    logging: false,
    synchronize: true,
  });
}
  • 通过使用上面的导出函数,我成功运行了单元测试,如下所示。
describe('UserService Logic Test', () => {
  let userService: UserService;
  let connection: Connection;
  let userRepository: Repository<User>;

  beforeAll(async () => {
    connection = await createMemoryDB([User]);
    userRepository = await connection.getRepository(User);
    userService = new UserService(userRepository);
  });

  afterAll(async () => {
    await connection.close();
  });

  afterEach(async () => {
    await userRepository.query('DELETE FROM users');
  });

  // testing codes.
});

我正在尝试在 e2e 测试中做同样的事情。我试过下面的代码。

// user.e2e-spec.ts

describe('UserController (e2e)', () => {
  let userController: UserController;
  let userService: UserService;
  let userRepository: Repository<User>;
  let connection: Connection;
  let app: INestApplication;
  const NAME = 'NAME';
  const EMAIL = 'test@test.com';
  const PASSWORD = '12345asbcd';

  beforeAll(async () => {
    connection = await createMemoryDB([User]);
    userRepository = await connection.getRepository(User);
    userService = new UserService(userRepository);
    userController = new UserController(userService);

    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [],
      controllers: [UserController],
      providers: [UserService],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  afterAll(async () => {
    await connection.close();
  });

  afterEach(async () => {
    // await userRepository.query('DELETE FROM users');
  });

  it('[POST] /user : Response is OK if conditions are right', () => {
    const dto = new UserCreateDto();
    dto.name = NAME;
    dto.email = EMAIL;
    dto.password = PASSWORD;

    return request(app.getHttpServer())
      .post('/user')
      .send(JSON.stringify(dto))
      .expect(HttpStatus.CREATED);
  });
});

我无法创建UserModule,因为它没有带有Connection 参数的构造函数。 代码本身没有编译错误,但在执行e2e测试时得到如下结果。

Nest can't resolve dependencies of the UserService (?). Please make sure that the argument UserRepository at index[0] is available in the RootTestModule context.

Potential solutions:
- If UserRepository is a provider, is it part of the current RootTestModule?
- If UserRepository is exported from a seperate @Module, is that module imported within RootTestModule?
  @Module({
    imports: [/* The module containing UserRepository */]
  })


TypeError: Cannot read property 'getHttpServer' of undefined.

任何帮助将不胜感激。谢谢:)


  • 更新:尝试以下操作后出现新错误。
describe('UserController (e2e)', () => {
  let userService: UserService;
  let userRepository: Repository<User>;
  let connection: Connection;
  let app: INestApplication;
  const NAME = 'NAME';
  const EMAIL = 'test@test.com';
  const PASSWORD = '12345asbcd';

  beforeAll(async () => {
    connection = await createMemoryDB([User]);
    userRepository = await connection.getRepository(User);
    userService = new UserService(userRepository);

    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [UserModule],
    })
      .overrideProvider(UserService)
      .useClass(userService)
      .compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  afterAll(async () => {
    await connection.close();
  });

  afterEach(async () => {
    await userRepository.query('DELETE FROM users');
  });

  it('[POST] /user : Response is OK if conditions are right', async () => {
    const dto = new UserCreateDto();
    dto.name = NAME;
    dto.email = EMAIL;
    dto.password = PASSWORD;

    const result = await request(app.getHttpServer())
      .post('/user')
      .send(JSON.stringify(dto))
      .expect({ status: HttpStatus.CREATED });
  });
});
  • 我检查了查询是否正常工作,并且能够看到它正在使用我想要的 SQLite 数据库。但是控制台出现了新的错误。
TypeError: metatype is not a constructor.

TypeError: Cannot read property 'getHttpServer' of undefined.

【问题讨论】:

    标签: javascript nestjs e2e-testing typeorm


    【解决方案1】:

    对于那些寻找命中端点并断言响应正文的设置 e2e 测试的人,您可以执行以下操作:

    // app.module.ts
    @Module({
      imports: [
        TypeOrmModule.forRootAsync({
          useFactory: async (configService: ConfigService) => {
            if (process.env.APPLICATION_ENV === 'test') {
              return {
                type: 'sqlite',
                database: ':memory:',
                entities: [Entity],
                synchronize: true,
              }
            }
            return {
              // your default options
            };
          },
        }),
      ]
    })
    

    【讨论】:

      【解决方案2】:

      好的,我通过在 Test.createTestingModule 的导入字段中使用 TypeOrm.forRoot() 解决了这个问题。以下是我的做法。

      describe('UserController (e2e)', () => {
        let userService: UserService;
        let userRepository: Repository<User>;
        let app: INestApplication;
        const NAME = 'NAME';
        const EMAIL = 'test@test.com';
        const PASSWORD = '12345asbcd';
      
        beforeAll(async () => {
          const moduleFixture: TestingModule = await Test.createTestingModule({
            imports: [
              UserModule,
              TypeOrmModule.forRoot({
                type: 'sqlite',
                database: ':memory:',
                entities: [User],
                logging: true,
                synchronize: true,
              }),
            ],
          }).compile();
      
          app = moduleFixture.createNestApplication();
          await app.init();
          userRepository = moduleFixture.get('UserRepository');
          userService = new UserService(userRepository);
        });
      
        afterAll(async () => {
          await app.close();
        });
      
        afterEach(async () => {
          await userRepository.query('DELETE FROM users');
        });
      });
      
      

      【讨论】:

      • 这对我真的很有帮助!感谢您自己的回答。
      • @CasimirCrystal 我的荣幸 :)
      猜你喜欢
      • 1970-01-01
      • 2020-11-16
      • 2021-02-24
      • 2022-10-06
      • 2020-10-28
      • 2021-03-02
      • 2015-04-11
      • 1970-01-01
      • 2020-09-01
      相关资源
      最近更新 更多