不要在框架NestJS中通过e2e测试

时间:2019-02-02 14:31:45

标签: javascript typescript e2e-testing nestjs typeorm

我使用 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 时,控制台会出现以下错误:

> bcs-life-insurance@0.0.0 test:e2e /home/nikita/MyFiles/Work/bcs-backend
> 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)

请帮帮我!

4 个答案:

答案 0 :(得分:6)

如果您想使用模拟编写e2e测试,则无需导入AppModule,而只需导入AppControllerAppService,这样就避免了连接到您的数据库并使用模拟来测试整个应用程序流。

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描述的新的数据库配置将其传递给测试模块。

我希望能有所帮助。 祝你好运。

答案 1 :(得分:1)

在单元测试中切勿使用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);
  }
}

希望有帮助!

答案 2 :(得分:0)

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

答案 3 :(得分:0)

即使您输入的api路径错误,也可能发生该错误。它不会记录错误,但始终会在您显示的那一行上引发。我也遇到类似的问题,我将globalPrefix放在/api上,在测试中我忘记了它的另一个嵌套应用程序实例,因此从e2e模拟中删除/ api /可以修复所有问题。