Testing Nest Applications

@nestjs/testing builds a module the same way the application does, and lets you replace any provider in it — the payoff for accepting dependency injection. One line does it: Test.createTestingModule({ providers: [BooksService, Store] }).overrideProvider(Store).useValue(stub).

End-to-end tests go further and build the whole application in memory, driven with Supertest 14,405 as in Docs and Tests. createNestApplication() never listens on a port, so the suite needs no free port and no teardown but app.close().

test/bookshelf.e2e-spec.ts — the real stack, no port, no databaseCSS
beforeEach(async () => {
  const mod = await Test.createTestingModule({ imports: [AppModule] }).compile();
  app = configure(mod.createNestApplication({ logger: false }));   // same pipes as main.ts
  await app.init();
});
it('refuses an anonymous POST with 401 and a reader with 403', async () => {
  const body = { title: 'Dawn', authorId: 'au_3', year: 1987, genre: 'sci-fi' };
  await request(app.getHttpServer()).post('/api/v1/books').send(body).expect(401);
  const res = await request(app.getHttpServer()).post('/api/v1/books')
    .set('Authorization', `Bearer ${reader}`).send(body).expect(403);
  expect(res.body.error.message).toBe('Requires one of: editor'); });

The trap is that configure(app) line: call it in the test too, or the global validation pipe is missing and you are testing an application you do not ship.

Output of 115
$ npx vitest run --config ./vitest.config.e2e.ts --reporter=verbose
 ✓ test/bookshelf.e2e-spec.ts > Bookshelf (e2e) > GET /api/v1/books pages the catalog 215ms
 ✓ rejects an out-of-range limit with 422 and lists every problem 27ms
 ✓ refuses an anonymous POST with 401 and a reader with 403 23ms
 ✓ accepts one review per reader, and answers 409 for the second 21ms
 Test Files  1 passed (1)      Tests  6 passed (6)      Duration  2.16s

A sixth case asserts on the generated document — expect(Object.keys(doc.paths)).toContain( '/api/v1/books/{id}/reviews'). Two lines, and it catches the failure nobody notices: a route that still works but dropped out of the published contract. A fresh testing module per test also gives a fresh Store singleton, so the cases share no state and run in any order.