【问题标题】:Do not pass e2e tests in framework NestJS不要在框架 NestJS 中通过 e2e 测试
【发布时间】:2019-06-26 21:16:38
【问题描述】:

我使用 NestJS 框架。使用 @nestjs/typeorm 时,我会创建一个包含用户的存储库。使用这种方法来创建存储库,我的 e2e 测试。使用数据库时,所有数据都已成功保存。连接没有问题。这是我的文件:

app.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Connection } from 'typeorm';
import { AuthModule } from './modules/auth/auth.module';

@Module({
  imports: [
    TypeOrmModule.forRoot(),
    AuthModule,
  ],
})
export class AppModule {
  constructor(private readonly connection: Connection) { }
}

auth.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { Users } from '../../entity/Users';

@Module({
  imports: [TypeOrmModule.forFeature([Users])],
  controllers: [AuthController],
  providers: [AuthService],
})
export class AuthModule {}

auth.service.ts

...
      // my repo
      constructor(
        @InjectRepository(Users)
        private readonly usersRepository: Repository<Users>,
      ) { }
...

app.e2e-spec.ts

import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';

describe('AppController (e2e)', () => {
  let app: INestApplication;

  beforeAll(async () => {
    const moduleFixture = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

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

  it('/ (GET)', () => {
    return request(app.getHttpServer())
      .get('/')
      .expect(404)
      .expect('{"statusCode":404,"error":"Not Found","message":"Cannot GET /"}'); //todo fix me
  });
});

一切都是按照文档编写的。当您运行 npm run test:e2e 时,控制台会出现以下错误:

> project@0.0.0 test:e2e 
> jest --config ./test/jest-e2e.json

[Nest] 7206   - 2/2/2019, 5:06:52 PM   [TypeOrmModule] Unable to connect to the database. Retrying (1)...
Error: getaddrinfo ENOTFOUND postgres postgres:5432
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)
[Nest] 7206   - 2/2/2019, 5:06:55 PM   [TypeOrmModule] Unable to connect to the database. Retrying (2)... +3234ms
Error: getaddrinfo ENOTFOUND postgres postgres:5432
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:57:26)
 FAIL  test/app.e2e-spec.ts (6.198s)
  AppController (e2e)
    ✕ / (GET) (6ms)

  ● AppController (e2e) › / (GET)

    Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.

      at mapper (../node_modules/jest-jasmine2/build/queue_runner.js:41:52)

  ● AppController (e2e) › / (GET)

    TypeError: Cannot read property 'getHttpServer' of undefined

      17 |
      18 |   it('/ (GET)', () => {
    > 19 |     return request(app.getHttpServer())
         |                        ^
      20 |       .get('/')
      21 |       .expect(404)
      22 |       .expect('{"statusCode":404,"error":"Not Found","message":"Cannot GET /"}'); // todo fix me

      at Object.<anonymous> (app.e2e-spec.ts:19:24)

请帮帮我!

【问题讨论】:

  • >无法连接到数据库。错误:getaddrinfo ENOTFOUND postgres postgres:5432
  • 你用什么来配置你的数据库连接?它取决于环境吗?运行测试的环境是否能够连接到该数据库? (例如,您是否在 docker 中运行测试,而 docker 无权访问该数据库?)
  • 我也有同样的问题

标签: javascript typescript e2e-testing nestjs typeorm


【解决方案1】:

如果你想用 mocks 编写 e2e 测试,你不需要导入 AppModule 你只需要导入你的 AppControllerAppService,这样你就可以避免连接到你的数据库并使用 mocks 来测试整个应用流程。

import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import * as request from 'supertest';
import { AppController } from './../src/app.controller';
import { AppService } from './../src/app.service';

describe('AppController (e2e)', () => {
  let app: INestApplication;

  beforeAll(async () => {
    const moduleFixture = await Test.createTestingModule({
      imports: [],
      controllers: [AppController],
      providers: [AppService],
    }).compile();

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

  it('/ (GET)', () => {
    return request(app.getHttpServer())
      .get('/')
      .expect(404)
      .expect('{"statusCode":404,"error":"Not Found","message":"Cannot GET /"}'); //todo fix me
  });
});

通过这种方法,您可以获得一个没有TypeOrmModule 的干净测试模块。 注意:如果你需要模拟服务,Test 有一个方法 overrideProvider 来覆盖你的服务和方法,如 useClassuseValueuseFactory 来提供你的模拟。

如果您想编写一个集成测试以确认所有功能都可以正常工作,您可以覆盖 TypeOrmModule 的配置,将其传递给测试模块,并使用新的数据库配置(如 this post 描述)。

我希望我有所帮助。 祝你好运和问候。

【讨论】:

    【解决方案2】:

    永远不要在单元测试中使用TypeOrmModule。它将连接到数据库。当您的数据库未启动时,您将无法运行单元测试。

    试试这个例子。

    // mytest.e2e-spec.ts
    import * as request from 'supertest';
    import { Test } from "@nestjs/testing";
    import { INestApplication } from '@nestjs/common';
    import { MyTestsController } from './myTests.controller';
    import { MyTestsService } from ".";
    import { Warehouse } from './myTest.entity';
    import { getRepositoryToken } from '@nestjs/typeorm';
    
    describe("MyTestsController (e2e)", () => {
    
      let app: INestApplication;
      const myTests = [
        {
          id: "1ccc2222a-8072-4ff0-b5ff-103cc85f3be6",
          name: "Name #1",
        }
      ];
    
      const myTestsCount = 1;
      const getAllResult = { myTests, myTestsCount };
      // Mock data for service
      let myTestsService = { getAll: () => getAllResult };
    
      beforeAll(async () => {
        const module = await Test.createTestingModule({
          providers: [
            MyTestsService,
            {
              provide: getRepositoryToken(Warehouse),
              useValue: myTestsService
            }
          ],
          controllers: [MyTestsController],
        })
          .overrideProvider(MyTestsService)
          .useValue(myTestsService)
          .compile();
    
        app = module.createNestApplication();
        await app.init();
      });
    
      beforeEach(async () => {});
    
      it(`/GET all myTests`, async() => {
        return await request(app.getHttpServer())
          .get('/myTests')
          .expect(200)
          .expect(myTestsService.getAll());
      });
    
      afterAll(async () => {
        await app.close();
      });
    
    });
    

    还有服务

    // myTests.service.ts
    public async getAll(query?): Promise<myTestsRO> {
      const qb = await this.repo.createQueryBuilder("myTests");
      const myTestsCount = await qb.getCount();
    
      if ("limit" in query) {
        qb.limit(query.limit);
      }
    
      if ("offset" in query) {
        qb.offset(query.offset);
      }
    
      const myTests = await qb
        .getMany()
        .then(myTests =>
          myTests.map(entity => WarehouseDto.fromEntity(entity))
        );
    
      return { myTests, myTestsCount };
    }
    

    和控制器

    // myTest.controller.ts
    @Get()
    public async getAll(@Query() query): Promise<myTestsRO> {
      try {
        return await this.myTestsService.getAll(query);
      } catch (error) {
        throw new InternalServerErrorException(error.message);
      }
    }
    

    希望对您有所帮助!

    【讨论】:

    • 他在做 e2e(端到端)测试,而不是单元测试。
    【解决方案3】:

    即使您输入错误的 api 路径,也会发生该错误。它不会记录错误,但它总是在您显示的那一行抛出。我也遇到了类似的问题,我将 globalPrefix 设置为 /api 并且在我的测试中我忘记了它是另一个嵌套应用程序实例,因此从 e2e 模拟中删除 /api/ 修复了所有问题。

    【讨论】:

      【解决方案4】:

      请务必按照https://docs.nestjs.com/fundamentals/testing#end-to-end-testing 的示例使用app.close() 关闭app 对象。

      【讨论】:

        猜你喜欢
        • 2021-02-24
        • 2022-10-06
        • 2020-11-16
        • 2020-09-01
        • 2021-05-17
        • 1970-01-01
        • 2019-12-28
        • 2020-10-28
        • 1970-01-01
        相关资源
        最近更新 更多