【问题标题】:Injecting Mocks in NestJS Application for Contract Testing在 NestJS 应用程序中注入 Mocks 以进行合同测试
【发布时间】:2019-04-13 07:05:01
【问题描述】:

问题

我正在寻找一种方法来启动带有模拟提供程序的 NestJS 应用程序。这对于提供者合同测试是必要的,因为需要单独提出服务。使用 Pact 库,测试提供者假定提供者服务已经在运行。它需要能够对实际服务器发出 HTTP 请求(必要时模拟一些依赖项)。 PactJS

当前研究

我查看了 NestJS 的文档,我能找到的最接近的解决方案粘贴在下面。据我所知,该解决方案告诉模块将任何名为CatsService 的提供程序替换为catsService。从理论上讲,这适用于提供者合同测试的目的,但我认为这不允许启动整个应用程序,而只是一个模块。文档中没有提到能够使用测试模块在特定端口上启动应用程序。我尝试在返回的 app 对象上调用 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);
  }
} 

【问题讨论】:

    标签: javascript node.js typescript nestjs pact


    【解决方案1】:

    更新

    从 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 请求,而不是依赖 supertest。 (我在这个例子中使用的是 nodejs 标准的 http 库。)

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

    【讨论】:

    • 我刚刚意识到关于listenAsync 的部分已经过时,但其余部分对我有用。我还可以在运行测试时在浏览器中请求该站点。我正在运行 5.3.5 版
    • 非常感谢!
    猜你喜欢
    • 2019-03-18
    • 1970-01-01
    • 2020-08-27
    • 2022-01-25
    • 2019-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-19
    相关资源
    最近更新 更多