일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- 공룡게임
- dfs
- 게임
- nodejs
- react
- MySQL
- class
- nestjs
- Python
- 정렬
- game
- typeORM
- Sequelize
- TypeScript
- cookie
- 자료구조
- Dinosaur
- AWS
- jest
- JavaScript
- MongoDB
- mongoose
- GIT
- flask
- Express
- Nest.js
- Bull
- OCR
- Queue
- Today
- Total
포시코딩
[Nest.js] Jest e2e test (app.e2e-spec.ts) 본문
개요
오늘도 헛소리 하는 다른 블로그들이 답답해서 내가 해결방법 찾아 정리해본다.
기본 세팅
app.e2e-spec.ts
import { Test, TestingModule } 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;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World!');
});
});
처음 Nest.js 프로젝트를 세팅하면 기본으로 이렇게 세팅되어 있을 것이다.
e2e 테스트를 무시하고 어느정도 개발했다는 상황으로 진행될 것이며
TypeOrmOptionFactory를 상속받는 TypeOrmConfigService를 만들어 사용하는 방식인 점 참고
사용한 파일들은 다음과 같다.
.env
DATABASE_HOST='localhost'
DATABASE_PORT=3306
DATABASE_USERNAME=''
DATABASE_PASSWORD=''
DATABASE_NAME=''
DATABASE_SYNC=true
TypeOrmConfigService
// ...import 생략
@Injectable()
export class TypeOrmConfigService implements TypeOrmOptionsFactory {
constructor(private readonly configService: ConfigService) {}
createTypeOrmOptions(): TypeOrmModuleOptions {
return {
type: 'mysql',
host: this.configService.get<string>('DATABASE_HOST'),
port: this.configService.get<number>('DATABASE_PORT'),
username: this.configService.get<string>('DATABASE_USERNAME'),
password: this.configService.get<string>('DATABASE_PASSWORD'),
database: this.configService.get<string>('DATABASE_NAME'),
synchronize: Boolean(this.configService.get<string>('DATABASE_SYNC')), // 배포 시 false
entities: [// ...Entity들 생략],
};
}
}
app.module.ts
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true, }),
TypeOrmModule.forRootAsync({ useClass: TypeOrmConfigService }),
// ...생략
여기서 app.module.ts를 아래와 같이 수정하고
ConfigModule.forRoot({
isGlobal: true,
envFilePath: process.env.NODE_ENV === 'test' ? '.env.test' : '.env',
}),
.env 파일을 복사해 .env.test 파일을 만들어
test 전용 DATABASE_NAME에 기존에 쓰는 DB 가 아닌 test용 DB를 바라보게 해준다.
(test용 DB는 수동으로 만들어야함)
이렇게만 해주면 npm run test:e2e 를 실행할 때 알아서 NODE_ENV=test 인 상태로 실행하는데
만약 했는데 DB를 원래 DB로 바라본다면
"test:e2e": "NODE_ENV=test jest --config ./test/jest-e2e.json"
이렇게 변경 후 테스트를 진행하자.
request 에러
시작하려고 딱 app.e2e-spec.ts 파일 열자마자 저렇게 빨간 밑줄 그어지며 에러가 나있는 상황이 있을 수 있다.
내가 그랬는데 아래와 같이 supertest를 import하는 부분을 * 대신 그냥 바로 request로 받게 변경하면 해결된다.
첫 e2e 테스트 - 테스트 후 앱 종료
이제 빨간줄이 없어졌으니
첫 e2e 테스트를 해보자
package.json
"test:e2e": "jest --config ./test/jest-e2e.json"
package.json에 나온대로
npm run test:e2e
위 명령어를 실행하면 된다.
실행하면 이렇게 성공했다는걸 볼 수 있는데 밑에 노란글이 거슬린다.
읽어보면 테스트가 끝난 이후 제대로 종료되지 않고 있어서 그렇다는건데
아래와 같이 코드를 수정해주자.
app.e2e-spec.ts
// ...import 생략
describe('AppController (e2e)', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
afterAll(async () => {
app.close();
});
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World');
});
});
기존에 beforeEach는 beforeAll로 바뀌었고,
afterAll을 추가해서 app.close()를 시키게 해줬다.
다시 아까와 같이 테스트를 실행하면
노란글 없이 깔끔하게 테스트를 마치는 걸 볼 수 있다.
Entity 경로 문제
실행 시 위 에러처럼 Cannot find module 모듈을 찾을 수 없다면서
찾을 수 없는 entity를 가리킨다.
검색해보면 대다수의 사람들이 상대경로로 바꾸면 해결된다고 하는데
개소리니 다음과 같이 진행하면 된다.
app.e2e-spec.ts 파일 바로 옆에 붙어 있는
jest-e2e.json 파일을 다음과 같이 수정한다.
jest-e2e.json
"moduleNameMapper": {
"^src/(.*)$": "<rootDir>/../src/$1"
}
세팅 후 다시 테스트 실행해보면 module 잘 찾으면서 성공하는 것을 볼 수 있다.
GET 테스트
이제 기존에 만들어놓은 get 요청에 대해 e2e 테스트를 진행해보자.
이미 만들어져 있는 기능 중 어떤 목록을 불러오는 get 요청을 할 것이다.
controller
대충 이렇게 생긴 controller 메서드인데 요약하자면
/api/meetups 로 GET 요청을 보내면 array를 리턴하는 메서드이다.
p와 keyword를 인자로 받고 있지만 기본값을 세팅해놔서 따로 아무것도 추가해줄 필요 없다.
app.e2e-spec.ts
describe('/api/meetups', () => {
it('GET 200', () => {
return request(app.getHttpServer())
.get('/api/meetups')
.expect(200)
.expect([]);
});
});
app.getHttpServer()는 localhost:포트번호 를 안쓰기 위해 사용했다.
보면 .get('/api/meeetups') 로 요청하고 있고
.expect(200) 을 통해 성공 시 200 status code를,
.expect([]) 를 통해 성공 시 빈 array 값을 리턴받는걸 예상하게끔 세팅해줬다.
테스트 실행해서 성공하는거 확인
POST 테스트
이제 POST 요청을 테스트해보자
describe('/api/auth', () => {
const signupBodyDTO: SignUpBodyDTO = {
email: 'test@gmail.com',
password: 'qwer1234',
}
it('POST 201', () => {
return request(app.getHttpServer())
.post('/api/auth/signup')
.send(signupBodyDTO)
.expect(201)
.expect({
message: '회원가입 되었습니다.',
});
});
});
회원가입 하는 POST 요청이다.
기본적으로 GET 요청과 비슷한데 다른점은 .send()를 통해 파라미터를 세팅하고 있다는 점이다.
위에서 미리 signupBodyDTO를 만들어 넣은 파라미터 오브젝트를 만든 후
.send()에 넣어주면서 POST 요청을 하고 있다.
또한 성공 시 201 status code와
{ message: '회원가입 되었습니다.' }
오브젝트를 받기 때문에 위와 같이 세팅해줬다.
실행 시 아까의 GET 요청과 더불어 성공하는 것을 볼 수 있다.
근데 테스트 DB Table을 확인해보니 방금 POST 요청한 데이터가 저장된 채로 남아있다.
이럴경우 다시 e2e 테스트를 한다면
이렇게 에러가 날 것이다.
테스트를 마칠 때 DB를 초기화 해주는 건 다음 항목에서 알아보자
Test DB Table 비우기
데이터가 그대로 남아있는건 테스트가 끝나면서 사리지게끔
따로 세팅을 안해줬기 때문인데 아래와 같이 수정하자.
app.e2e-spec.ts
import { Connection } from 'typeorm';
describe('AppController (e2e)', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
const connection = app.get(Connection);
await connection.synchronize(true);
await app.init();
});
afterAll(async () => {
const connection = app.get(Connection);
await connection.synchronize(true);
app.close();
});
beforeAll, afterAll 에서
const connection = app.get(Connection);
await connection.synchronize(true);
위 두 코드가 추가된 것을 볼 수 있다.
Connection은 typeorm에서 가져온 애인데
빗금이 쳐져있고 살펴보면 더 이상 지원되지 않기에 is deprecated. 라고 되어있다.
좀 찾아본 결과 typeorm이 0.2x에서 0.3.x로 업데이트 되며 바뀐 부분이라 그렇다는데
다른 걸 쓰는 방법을 좀 찾아보았으나 실패하여 위 방법 그대로 진행.
만약 다른 해결방법을 안다면 제발 알려주세요.
아무튼 이렇게 변경한 후 다시 테스트를 실행해보면
DB에 데이터 추가 없이 성공하는 것을 볼 수 있다.
정리
이제 나머지 API에 대해서는 위의 방법을 응용해 작성해보자.
사실 나도 위의 GET, POST 요청만 작성하고 바로 포스팅하는거라 이제 나머지 작성해야함.
위 글 이후 작성되는 코드에 대한건
https://github.com/chalkak2023/Chalkak-Backend
위 repo에서 확인이 가능할듯 싶다. 계속 업데이트중
도움받은 곳
수많은 Nest.js e2e 관련 글들 중에서 아래 두 분의 블로그 포스팅에서 많은 도움을 받아 작성됐다.
https://darrengwon.tistory.com/1049
https://puleugo.tistory.com/114
'Node.js' 카테고리의 다른 글
[Nest.js] 쿠키를 받지 못하는 문제 (상용 서버) (0) | 2023.03.13 |
---|---|
[Nest.js] 동시성 문제 다루기 with. JMeter, Bull Queue, event-emitter (0) | 2023.03.08 |
[Nest.js] TableInheritance을 통한 entity 상속 (0) | 2023.03.06 |
[Nest.js][CORS] GET 요청에서 cookie를 전달받지 못하는 문제 (0) | 2023.03.02 |
[Nest.js] 이메일 인증 시스템 (3). Redis 적용 (1) | 2023.02.24 |