6
votes

Ne passez pas les tests e2e dans le framework NestJS

J'utilise le framework NestJS . Lorsque j'utilise @ nestjs / typeorm , je crée un référentiel avec les utilisateurs. En utilisant cette approche pour créer un référentiel, mes tests e2e . Lorsque vous travaillez avec une base de données, toutes les données sont enregistrées avec succès. Il n'y a aucun problème avec la connexion. Voici mes fichiers:

app.module.ts

> 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)

auth.module.ts p >

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
  });
});

auth.service.ts

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

app.e2e-spec.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 {}

Tout est écrit conformément à la documentation. Lorsque vous exécutez npm run test: e2e , la console renvoie l'erreur suivante:

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) { }
}

S'il vous plaît, aidez-moi!

p >


3 commentaires

> Impossible de se connecter à la base de données. Erreur: getaddrinfo ENOTFOUND postgres postgres: 5432


Qu'utilisez-vous pour configurer votre connexion à la base de données? Est-ce quelque chose qui dépend de l'environnement? L'environnement sur lequel les tests sont exécutés est-il capable de se connecter à cette base de données? (par exemple, exécutez-vous les tests dans docker et docker n'a pas accès à cette base de données?)


J'ai le même problème


4 Réponses :


1
votes

Assurez-vous de fermer l'objet app avec app.close () selon l'exemple à https://docs.nestjs.com/fundamentals/testing#end-to-end-testing .


0 commentaires

0
votes

Cette erreur peut se produire même si vous avez mal tapé les chemins de votre API. Il n'enregistre pas l'erreur mais il jette toujours sur cette ligne que vous avez affichée. J'ai également eu un problème similaire, je mettais globalPrefix dans / api et dans mes tests, j'ai oublié que c'était une autre instance d'application Nest, donc la suppression de / api / de e2e simulait tout.


0 commentaires

0
votes

N'utilise jamais TypeOrmModule dans le test unitaire. Ce sera se connecter à DB. Lorsque votre base de données n'a pas démarré, vous ne pourrez pas exécuter de test unitaire.

Essayez cet exemple.

// 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);
  }
}

Et le service

// 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 };
}

Et le contrôleur

// 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();
  });

});

J'espère que cette aide!


1 commentaires

Il fait des tests e2e (de bout en bout), pas des tests unitaires.



6
votes

Si vous souhaitez écrire des tests e2e avec des simulations, vous n'avez pas besoin d'importer le AppModule , vous devez uniquement importer votre AppController et AppService , de cette façon, vous évitez de vous connecter à votre base de données et d'utiliser des simulations pour tester l'ensemble du flux d'application.

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
  });
});

Avec cette approche, vous obtenez un module de test propre sans TypeOrmModule . REMARQUE: si vous devez vous moquer du service, le Test a une méthode overrideProvider pour remplacer votre service et des mothods comme useClass , useValue ou useFactory pour fournir votre maquette.

Si vous voulez écrire un test d'intégration pour confirmer que tout fonctionne bien, vous pouvez remplacer la configuration de votre TypeOrmModule , en le transmettant au module de test avec une nouvelle configuration de base de données comme décrit ce post .

J'espère avoir aidé. Bonne chance et salutations.


0 commentaires