javascript - 在 NestJS 應用中注入模擬以進行契約測試
問題
我正在尋找一種方法來啟動具有模擬提供者的 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);
}
}
答案#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());
