ํฐ์คํ ๋ฆฌ ๋ทฐ
๐ NestJS ๋ฐฑ์๋ ๊ฐ๋ฐ: ๊ธฐ์ด๋ถํฐ ์ค์ ๊น์ง - NestJS์์ ํ ์คํธ ์์ฑ๊ณผ TDD ์ค์ฒ
octo54 2025. 3. 22. 11:53๐ NestJS ๋ฐฑ์๋ ๊ฐ๋ฐ: ๊ธฐ์ด๋ถํฐ ์ค์ ๊น์ง - NestJS์์ ํ ์คํธ ์์ฑ๊ณผ TDD ์ค์ฒ
์๋น์ค์ ์์ ์ฑ๊ณผ ์ ๋ขฐ์ฑ์ ๋ณด์ฅํ๋ ค๋ฉด ํ
์คํธ๋ ์ ํ์ด ์๋ ํ์์
๋๋ค.
NestJS๋ Jest ๊ธฐ๋ฐ์ ํ
์คํธ ํ๊ฒฝ์ ๊ธฐ๋ณธ์ผ๋ก ์ ๊ณตํ๋ฉฐ, ํ
์คํธ ์ฃผ๋ ๊ฐ๋ฐ(TDD)์ ์ฝ๊ฒ ์คํํ ์ ์๋๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
์ด๋ฒ ๊ธ์์๋ ์ ๋ ํ
์คํธ(Unit Test), ํตํฉ ํ
์คํธ(E2E Test), Mocking ์ ๋ต, TDD ํ๋ฆ ์์ ๋ฅผ ๋ค๋ฃน๋๋ค. ๐
12.1 NestJS์์์ ํ ์คํธ ํ๊ฒฝ
NestJS๋ ํ๋ก์ ํธ๋ฅผ ์์ฑํ๋ฉด ์๋์ผ๋ก Jest ํ๊ฒฝ์ด ์ค์ ๋ฉ๋๋ค.
โ ๊ธฐ๋ณธ ํ ์คํธ ๊ตฌ์ฑ ํ์ผ๋ค
- jest.config.ts: Jest ์ค์ ํ์ผ
- test/app.e2e-spec.ts: ๊ธฐ๋ณธ End-to-End ํ ์คํธ
- ๊ฐ ๋ชจ๋๋ง๋ค *.spec.ts ํํ๋ก ์ ๋ ํ ์คํธ ์์ฑ ๊ฐ๋ฅ
๐ก NestJS CLI๋ ํ ์คํธ ์ฝ๋ ์์ฑ์ ์๋ํํด์ค๋๋ค.
12.2 ์ ๋ ํ ์คํธ (Unit Test)
์ ๋ ํ ์คํธ๋ ์๋น์ค๋ ์ ํธ๋ฆฌํฐ ํจ์์ฒ๋ผ ์์ ๋จ์์ ๋ก์ง์ ๊ฒ์ฆํ๋ ํ ์คํธ์ ๋๋ค.
โ ์๋น์ค ์ ๋ ํ ์คํธ ์์
๐ users.service.ts
@Injectable()
export class UsersService {
private users = [{ id: 1, name: 'Alice' }];
findAll() {
return this.users;
}
findOne(id: number) {
return this.users.find(user => user.id === id);
}
}
๐ users.service.spec.ts
import { UsersService } from './users.service';
describe('UsersService', () => {
let service: UsersService;
beforeEach(() => {
service = new UsersService();
});
it('should return all users', () => {
expect(service.findAll()).toHaveLength(1);
});
it('should return a user by ID', () => {
expect(service.findOne(1)).toEqual({ id: 1, name: 'Alice' });
});
});
โ
beforeEach()๋ฅผ ํตํด ๋งค ํ
์คํธ๋ง๋ค fresh ์ธ์คํด์ค ์์ฑ
โ
expect()๋ก ํ
์คํธ ๊ฒฐ๊ณผ ๊ฒ์ฆ
12.3 ์์กด์ฑ ์ฃผ์ ์ด ์๋ ์๋น์ค ํ ์คํธ
NestJS๋ DI ์ปจํ ์ด๋๋ฅผ ์ฌ์ฉํ๋ฏ๋ก, ํ ์คํธ์์๋ TestingModule์ ํตํด ์์กด์ฑ์ ์ฃผ์ ํด์ผ ํฉ๋๋ค.
import { Test, TestingModule } from '@nestjs/testing';
import { UsersService } from './users.service';
describe('UsersService', () => {
let service: UsersService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [UsersService],
}).compile();
service = module.get<UsersService>(UsersService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
๐ก NestJS์ Test.createTestingModule์ ํ์ฉํ๋ฉด ์ค์ ์๋น์ค์ฒ๋ผ ํ ์คํธ ๊ตฌ์ฑ ๊ฐ๋ฅ
12.4 ์ปจํธ๋กค๋ฌ ํ ์คํธ (Mocking ํฌํจ)
๐ users.controller.ts
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll() {
return this.usersService.findAll();
}
}
๐ users.controller.spec.ts
describe('UsersController', () => {
let controller: UsersController;
let service: UsersService;
beforeEach(async () => {
const module = await Test.createTestingModule({
controllers: [UsersController],
providers: [
{
provide: UsersService,
useValue: {
findAll: jest.fn().mockReturnValue([{ id: 1, name: 'MockUser' }]),
},
},
],
}).compile();
controller = module.get<UsersController>(UsersController);
service = module.get<UsersService>(UsersService);
});
it('should return mocked users', () => {
expect(controller.findAll()).toEqual([{ id: 1, name: 'MockUser' }]);
});
});
โ
์ค์ ์๋น์ค ๋์ mock ๊ฐ์ฒด๋ฅผ ์ฃผ์
โ
jest.fn()์ผ๋ก ๋ฉ์๋ ๋ชจํน ๋ฐ ๋ฐํ ๊ฐ ์ง์
12.5 E2E ํ ์คํธ (End-to-End)
E2E ํ ์คํธ๋ ์ค์ ์๋ฒ๋ฅผ ์คํํ๊ณ , ์ ์ฒด ํ๋ฆ์ ํตํฉ์ ์ผ๋ก ํ ์คํธํฉ๋๋ค.
๐ test/app.e2e-spec.ts
import { Test } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
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(200)
.expect('Hello World!');
});
});
โ
supertest๋ฅผ ํตํด ์ค์ HTTP ์์ฒญ์ ๋ณด๋ด ํ
์คํธ
โ
app.getHttpServer()๋ก NestJS ์ธ์คํด์ค ๊ธฐ๋ฐ ์๋ฒ ์ ๊ทผ
12.6 TDD(Test Driven Development) ํ๋ฆ
TDD๋ ๋ค์์ ์์๋ก ํ ์คํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ๋ฐ์ ์งํํฉ๋๋ค:
- Fail: ๋จผ์ ์คํจํ๋ ํ ์คํธ๋ฅผ ์์ฑ
- Pass: ํ ์คํธ๊ฐ ํต๊ณผํ๋๋ก ์ต์ํ์ ์ฝ๋ ์์ฑ
- Refactor: ํ ์คํธ๊ฐ ํต๊ณผ๋ ์ํ์์ ๋ฆฌํฉํ ๋ง
๐ก ํ ์คํธ ์ฝ๋๋ฅผ ๋จผ์ ์์ฑํ๋ฉด ์๊ตฌ์ฌํญ์ ๋ง์ถ ์์ ์ ์ธ ์ฝ๋ ๊ตฌํ ๊ฐ๋ฅ
12.7 ํ ์คํธ ์คํ ๋ฐ ์ปค๋ฒ๋ฆฌ์ง ํ์ธ
โ ํ ์คํธ ์คํ
npm run test
โ ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง ํ์ธ
npm run test:cov
์ถ๋ ฅ ์์:
File | % Stmts | % Branch | % Funcs | % Lines |
-----------------------|---------|----------|---------|---------|
src/users/users.service.ts | 100% | 100% | 100% | 100% |
๐ก ์ปค๋ฒ๋ฆฌ์ง ๋๊ตฌ๋ฅผ ํตํด ํ ์คํธ ๋ฒ์๋ฅผ ์๊ฐ์ ์ผ๋ก ํ์ธ ๊ฐ๋ฅ
12.8 ๊ฒฐ๋ก : NestJS ํ ์คํธ์ TDD๋ก ์ ๋ขฐ์ฑ ์๋ ์ฝ๋ ๋ง๋ค๊ธฐ
โ
NestJS๋ Jest ๊ธฐ๋ฐ์ ์ ๋ & ํตํฉ ํ
์คํธ ํ๊ฒฝ์ ๊ธฐ๋ณธ ์ ๊ณต
โ
TestingModule๋ก DI ์ฃผ์
ํ
์คํธ ๊ฐ๋ฅ
โ
์๋น์ค, ์ปจํธ๋กค๋ฌ, E2E ํ
์คํธ๊น์ง ์์ ํ ํ
์คํธ ์ฒด๊ณ ๊ตฌ์ถ ๊ฐ๋ฅ
โ
TDD ๋ฐฉ์์ผ๋ก ๊ฐ๋ฐ ์ ์์ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ด ๋ํญ ํฅ์๋จ
๋ค์ ๊ธ์์๋ NestJS ํ๋ก์ ํธ์ ๊ตฌ์กฐ ์ ๋ฆฌ์ ๋ชจ๋ ธ๋ ํฌ(Monorepo) ํจํด ์ ์ฉ๋ฒ์ ์๊ฐํฉ๋๋ค! ๐
๐ ๋ค์ ๊ธ ์๊ณ : NestJS ํ๋ก์ ํธ ๊ตฌ์กฐ ์ ๋ฆฌ ๋ฐ ๋ชจ๋ ธ๋ ํฌ ๊ตฌ์ฑ ์ ๋ต
๐ ๋ค์ ํธ: 13. NestJS ๋ชจ๋ ธ๋ ํฌ ๊ตฌ์กฐ์ ์ค์ ์ ์ฉ๋ฒ
'study > ๋ฐฑ์๋' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
- Total
- Today
- Yesterday
- kotlin
- ํ๋ก ํธ์๋
- gatsbyjs
- PostgreSQL
- REACT
- ์น๊ฐ๋ฐ
- SEO ์ต์ ํ
- seo ์ต์ ํ 10๊ฐ
- App Router
- ๊ด๋ฆฌ์
- fastapi
- ์ค๋งํธ ์ปจํธ๋ํธ
- llm
- AI์ฑ๋ด
- nextJS
- ๋ฐฑ์๋๊ฐ๋ฐ
- nodejs
- ๊ฐ๋ฐ๋ธ๋ก๊ทธ
- LangChain
- NestJS
- Prisma
- AI ์๋ํ
- Next.js
- SEO์ต์ ํ
- Docker
- rag
- github
- Ktor
- Webpack
- CI/CD
์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |