簡體   English   中英

在 e2e 測試 NestJS 時使用測試數據庫

[英]Using test database when e2e-testing NestJS

在這個項目中,它使用 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,
  });
}
  • 通過使用上面導出的 function,我成功地運行了單元測試,如下所示。
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.

好的,我通過在 Test.createTestingModule 的導入字段中使用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');
  });
});

對於那些尋找命中端點並斷言響應主體的設置 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
        };
      },
    }),
  ]
})

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM