Инъекция насмешек в приложении NestJS для тестирования контрактов - PullRequest
0 голосов
/ 09 ноября 2018

Выпуск

Я ищу способ вызвать приложение NestJS с помощью издевательских провайдеров. Это необходимо для тестирования контракта с поставщиком, потому что сервис должен быть изолирован в отдельности. При использовании библиотеки Pact при тестировании провайдера предполагается, что сервис провайдера уже запущен. Он должен иметь возможность отправлять HTTP-запросы к реальному серверу (при необходимости проверять некоторые зависимости). PactJS

Текущие исследования

Я посмотрел документы для NestJS, и самое близкое решение, которое я могу найти, вставлено ниже. Из того, что я могу сказать, это решение говорит модулю заменить любого провайдера с именем CatsService на catsService. Теоретически это будет работать в целях тестирования контракта с провайдером, но я не думаю, что это позволяет запустить все приложение, только модуль. В документации нет упоминания о возможности запуска приложения на определенном порту с помощью модуля тестирования. Я попытался вызвать app.listen для возвращенного объекта приложения, и он не может достичь точки останова, установленной сразу после вызова.

import * as request from "supertest";
import { Test } from "@nestjs/testing";
import { CatsModule } from "../../src/cats/cats.module";
import { CatsService } from "../../src/cats/cats.service";
import { INestApplication } from "@nestjs/common";

describe("Cats", () => {
  let app: INestApplication;
  let catsService = { findAll: () => ["test"] };

  beforeAll(async () => {
    const module = await Test.createTestingModule({
      imports: [CatsModule]
    })
      .overrideProvider(CatsService)
      .useValue(catsService)
      .compile();

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

  it(`/GET cats`, () => {
    return request(app.getHttpServer())
      .get("/cats")
      .expect(200)
      .expect({
        data: catsService.findAll()
      });
  });

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

Пример Java

Используя Spring в классе конфигурации, макеты могут быть внедрены в приложение при работе с профилем "contract-test".

@Profile({"contract-test"})
@Configuration
public class ContractTestConfig {

  @Bean
  @Primary
  public SomeRepository getSomeRepository() {
    return mock(SomeRepository.class);
  }

  @Bean
  @Primary
  public SomeService getSomeService() {
    return mock(SomeService.class);
  }
} 

1 Ответ

0 голосов
/ 09 ноября 2018

Обновление

Начиная с версии 4.4 вы также можете использовать listen, поскольку теперь она также возвращает Promise.


Вы должны использовать метод listenAsync вместо listen, чтобы вы могли использовать его с await:

beforeAll(async () => {
  const moduleFixture = await Test.createTestingModule({
    imports: [AppModule],
  })
    .overrideProvider(AppService).useValue({ root: () => 'Hello Test!' })
    .compile();

  app = moduleFixture.createNestApplication();
  await app.init();
  await app.listenAsync(3000);
        ^^^^^^^^^^^^^^^^^^^^^
});

Тогда вы можете делать реальные http-запросы вместо того, чтобы полагаться на супертест. (В этом примере я использую стандартную http-библиотеку nodejs.)

import * as http from 'http';

// ...

it('/GET /', done => {
  http.get('http://localhost:3000/root', res => {
    let data = '';
    res.on('data', chunk => data = data + chunk);
    res.on('end', () => {
      expect(data).toEqual('Hello Test!');
      expect(res.statusCode).toBe(200);
      done();
    });
  });
});

Не забудьте закрыть приложение, иначе ваш тест будет выполняться до тех пор, пока он не будет закрыт вручную.

afterAll(() => app.close());
...