ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • nestjs에서 jest TIP 정리
    NodeJS 2022. 11. 7. 15:08

    전체 테스트 코드 예제

    import { Test, TestingModule } from '@nestjs/testing';
    import { INestApplication } from '@nestjs/common';
    import request from 'supertest';
    import { AppModule } from './../src/app.module';
    import { CmmCodeMController } from '../src/modules/cmm-code-m/cmm-code-m-adm.controller';
    import { ValidationPipe } from '@nestjs/common';
    import { AuthAdminGuard } from './../src/commons/modules/auth/auth.admin.guard';
    import { getRepository, Repository } from 'typeorm';
    import { CmmCodeM } from '../src/entities/cmm-code-m.entity';
    import { getRepositoryToken } from '@nestjs/typeorm';
    import { mockAuthAdminGuard } from './mockAuthGuard';
    
    describe('AppController (e2e)', () => {
      let app: INestApplication;
      let repository: Repository<CmmCodeM>
      beforeAll(async () => {
    
        const moduleFixture: TestingModule = await Test.createTestingModule({
          imports: [AppModule],
          providers: [{
            provide: getRepositoryToken(CmmCodeM),
            useClass: Repository,
          },],
        })
          .overrideGuard(AuthAdminGuard).useValue(mockAuthAdminGuard)
          .compile();
    
        app = moduleFixture.createNestApplication();
        repository = getRepository(CmmCodeM);
        // app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));
        // app.useGlobalInterceptors(
        //   new ClassSerializerInterceptor(app.get(Reflector)),
        // );
        app.useGlobalPipes(new ValidationPipe({ transform: true }));
    
        await app.init();
      });
    
      it('/ (GET)', () => {
        return request(app.getHttpServer())
          .get('/')
          .expect(200)
          .expect('Hello World!');
      });
    
      // 공통 코드 처리
      describe('공통 코드 CRUD 테스트', () => {
    
        let cmmCdcontroller;
        it('should be defined', async () => {
          cmmCdcontroller = await app.get(CmmCodeMController);
          expect(cmmCdcontroller).toBeDefined();
        });
    
        let codeId;
        it('코드 등록 실패', async () => {
          // 필수 정보 누락으로 오류 발생
          const response = await request(app.getHttpServer())
            .post('/adm/codeM')
            .send({
              cmmCdVal: 'string',
              uprCmmGrpCd: 'string',
              seq: 0,
              expsYn: 'Y',
            })
            .expect(400);
          const result = JSON.parse(response.text);
          expect(result.statusCode).toEqual(400);
          expect(result.error).toEqual('Bad Request');
    
        });
    
        it('코드 등록', async () => {
          const response = await request(app.getHttpServer())
            .post('/adm/codeM')
            .send({
              cmmGrpCd: 'string',
              cmmCdNm: 'string',
              cmmCdVal: 'string',
              uprCmmGrpCd: 'string',
              seq: 0,
              expsYn: 'Y',
            })
            .expect(201);
          codeId = JSON.parse(response.text).id;
          expect(codeId).toBeDefined();
        });
    
        it('전체 코드 조회', async () => {
          const response = await request(app.getHttpServer())
            .get('/adm/codeM')
            .expect(200);
          expect(JSON.parse(response.text).total).toBeGreaterThan(0);
    
        });
    
        it('특정 코드 조회', async () => {
          const response = await request(app.getHttpServer())
            .get(`/adm/codeM/${codeId}`)
            .expect(200);
    
          expect(JSON.parse(response.text).id).toEqual(codeId);
        });
    
    
        it('코드 수정', async () => {
          const response = await request(app.getHttpServer())
            .put(`/adm/codeM/${codeId}`)
            .send({
              cmmGrpCd: 'string',
              cmmCdNm: 'string',
              cmmCdVal: 'string',
              uprCmmGrpCd: 'string',
              seq: 0,
              expsYn: 'Y',
              id: codeId,
            })
            .expect(200);
          expect(JSON.parse(response.text).affected).toEqual(1);
        });
    
        it('코드 삭제', async () => {
          const response = await request(app.getHttpServer())
            .delete(`/adm/codeM/${codeId}`)
            .expect(200);
          expect(JSON.parse(response.text).affected).toEqual(1);
        });
    
        it('실제 데이터 삭제 처리', async () => {
          const result = await repository.delete(codeId);
          expect(result.affected).toEqual(1);
        });
      });
      afterAll(async () => {
        app.close();
      });
    });
    

    한개의 테스트 파일 실행

    특정 파일 한개만 실행하기 위해 여러 명령어를 테스트 해보았으나, 제공되는 config를 사용하고 옵션을 command로 추가 선언하는 방식으로 처리하였습니다.

    a.test.ts, b.test.ts 이렇게 파일이 2개 있을때, a.test.ts만을 실행하기 위해서는 다음의 명령어를 이용합니다.

    # node_modules/jest-cli/bin/jest.js --config ./test/jest-e2e.json --testRegex "파일명" 
    $ node_modules/jest-cli/bin/jest.js --config ./test/jest-e2e.json --testRegex app.e2e-spec.ts
    

    종료 처리

    테스트 실행시, 아래와 같이 경고가 뜨고 종료가 되지 않을 경우가 많이 있습니다. 검색을 해보면 원인으로 DB 커넥션이 완전히 close 되지 않아서 발생한다고 하는데, 여러 방안을 테스트 해보았지만 결국 테스트 종료후 강제 종료로 처리 하였습니다.

     PASS  test/app.e2e-spec.ts (6 s)
      AppController (e2e)
        ✓ / (GET) (24 ms)
        공통 코드 CRUD 테스트
          ✓ should be defined (1 ms)
          ✓ 코드 등록 실패 (44 ms)
          ✓ 코드 등록 (130 ms)
          ✓ 전체 코드 조회 (37 ms)
          ✓ 특정 코드 조회 (19 ms)
          ✓ 코드 수정 (50 ms)
          ✓ 코드 삭제 (44 ms)
          ✓ 실제 데이터 삭제 처리 (19 ms)
    
    Test Suites: 1 passed, 1 total
    Tests:       9 passed, 9 total
    Snapshots:   0 total
    Time:        6.051 s
    Ran all test suites.
    Jest did not exit one second after the test run has completed.
    
    This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
    

    해결 방법으로 Jest has detected the following 1 open handle potentially keeping Jest from exiting: TCPSERVERWRAP 에 나온 옵션인 --forceExit 을 추가해서 처리 하세요.

    $ node_modules/jest-cli/bin/jest.js --config ./test/jest-e2e.json --testRegex "파일명" --forceExit
    

    참고 자료

Designed by Tistory.