F.I.R.S.T 원칙은 단위 테스트가 가져야 할 특성과 원칙에 관해서 이야기하고 있습니다.

Fast

단위 테스트는 빨라야 한다.

- 빠른 실행은 개발 과정에서 테스트를 자주 수행할 수 있게 하고, 즉각적인 피드백을 제공하여 개발 속도를 향상시킵니다.

Isolated

단위 테스트는 외부 요인에 종속적이지 않고 독립적으로 실행되어야 한다.

- 하나의 테스트 당 하나의 기능만을 테스트해야 문제의 원인을 좁혀가는데 도움이 됩니다.

Repeatable

단위 테스트는 실행할 때마다 같은 결과를 만들어야 한다.

- 테스트가 외부 환경이나 상태에 의존하지 않고 일관된 결과를 보장하도록 함으로써, 신뢰할 수 있는 테스트 환경을 조성해야합니다.

Self-validating

단위 테스트는 스스로 테스트를 통과했는지 아닌지 판단할 수 있어야 한다.

-테스트 결과를 간단하게 '성공' 또는 '실패'로 판단할 수 있게 하여, 결과 해석에 대한 모호성을 제거하고 자동화된 테스트 실행이 가능하게 합니다.

Timely

단위 테스트는 프로덕션 코드가 테스트에 성공하기 전에 구현되어야 한다. 

- 개발 초기에 문제를 발견하고 해결함으로써, 나중에 발생할 수 있는 복잡한 버그와 관련 비용을 줄일 수 있습니다.

 

 

 

 

참고자료

https://techblog.woowahan.com/17404/

https://velog.io/@sdb016/%EC%A2%8B%EC%9D%80-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8-FIRST%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC

사용할 로그 레벨별 메세지 서비스 작성 및 모듈작성

logger.service.ts

import { ConsoleLogger, Injectable } from '@nestjs/common';

@Injectable()
export class LoggerService extends ConsoleLogger {

  log(message: any, ...optionalParams: any[]) {
    super.log(`${message}`, ...optionalParams);
  }

  error(message: any, ...optionalParams: any[]) {
    super.error(` ${message}`, ...optionalParams);
  }

  warn(message: any, ...optionalParams: any[]) {
    super.warn(` ${message}`, ...optionalParams);
  }

  debug(message: any, ...optionalParams: any[]) {
    super.debug(`${message}`, ...optionalParams);
  }
}

 

logger.module.ts

import { Module } from '@nestjs/common';
import { LoggerService } from './logger.service';

@Module({
  providers: [LoggerService],
  exports: [LoggerService],
})
export class LoggerModule {}

 

메인에 설정

main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ConfigService } from '@nestjs/config';
import { ValidationPipe } from '@nestjs/common';
import { initializeTransactionalContext } from 'typeorm-transactional';
// 추가된 코드
import { LoggerService } from './common/Logger/logger.service';

async function bootstrap() {
  initializeTransactionalContext();
  const app = await NestFactory.create(AppModule, { bufferLogs: true });// 로그설정
  app.useLogger(app.get(LoggerService));// 서비스 설정
  app.useGlobalPipes(
    new ValidationPipe({
      transform: true,
    }),
  );
  const configService = app.get(ConfigService);
  const port = configService.get<string>('PORT') as string;
  const hostIP = configService.get<string>('HOST_IP') as string;
  await app.listen(port, hostIP);
  console.log(`Application is running on: ${await app.getUrl()}`);
}
bootstrap();

 

 

app api 에 적용

app.controller.ts

import ....

@Controller('routines')
export class RoutineController {
  // 로그 헤더에 표시됨 -> [AppController] (message)
  // 해당 컨트롤러에 맞게 변경
  private readonly logger = new Logger(AppController.name); 
  constructor(private readonly routineService: RoutineService) {}


  @Get()
  @UseGuards(JwtAuthGuard)
  getRoutine(@Body() getRoutineRequest: GetRoutineRequestDto, @Request() req: any) {
    this.logger.log(`start getRoutine DTO : ${getRoutineRequest.name}`); // 로그 생성
    return this.routineService.getRoutineByName(getRoutineRequest, req.user);
  }
  ...
}

 

app.service.ts

import ...

@Injectable()
export class AppService {
  // 해당 서비스에 맞게 변경 ex)PostService.name
  private readonly logger = new Logger(AppService.name);
  constructor(
  	....
  ) {}


  async getRoutineByName(getRoutineRequest: GetRoutineRequestDto, user: User) {
    const { name } = getRoutineRequest;
    const routines = await this.routineRepository.findOne({where:{name}});
    if(!routines){
       this.logger.log(`Routines using name:'${name}' can not find`);
       throw new BadRequestException(`Routines using name:'${name}' can not find`);
    }
   
    this.logger.log(`found routines using ${name}`);
    return routines;
  }

}

 

 

참고자료

https://docs.nestjs.com/techniques/logger

라이브러리 설치

$ npm init
$ npm i -D jest ts-jest @jest/globals @types/jest

 

ts-jest config 파일 생성

$ npx ts-jest config:init

 

1.  간단한 테스트 및 셋팅

테스트 작성할 파일 생성 :  "xxx.spec.ts" 혹은 "xxx.test.ts" 로 생성

      app.spec.ts 에 아래코드를 작성

function sum (a: number, b: number): number {
    return a + b;
}

test(`1 + 2 는 3이다.`, ()=>{
    expect(sum(1, 2)).toBe(3);
})

      

      package.json 에 아래 설정 추가

{
  ...
  "scripts": {
    "test": "jest"
  }
  ...
}

 

      터미널에서 테스트 실행

 $ npm test
 
 PASS  ./app.spec.ts
  ✓ 1 + 2 는 3이다. (1 ms)

 

참고자료

https://kulshekhar.github.io/ts-jest/docs/getting-started/installation/

 

먼저 webstorm -> setting 으로 이동

Prettier

 

 

ESLint

 

 

라이브러리 설치

$ npm i bcrypt
$ npm i -D @types/bcrypt

 

비밀번호 암호화하기

  async signUp(signUpRequestDto: SignUpRequestDto) {
    const { email, password } = signUpRequestDto;
    const user = new User();
    user.email = email;
    const hashedPassword = await bcrypt.hash(password, 10);
    user.password = hashedPassword;
    return await this.userRepository.save(user);
  }

 

saltround 를 .env 파일에서 호출하여 넣을 때

호출한 값의 데이터 타입 = string 이므로 아래와 같이 확인 절차를 걸쳐서 number 로 변환해주어야 한다.

const saltRounds = this.configService.get<string>('SALT_ROUNDS');
if (saltRounds === undefined) {
    throw new Error('SALT_ROUNDS is not defined in the configuration.');
}
const hashedPassword = await bcrypt.hash(password, parseInt(saltRounds));

 

 

signIn 을 할때는  아래 코드를 이용하여 입력된 패스워드와 DB에 저장된 패스워드가 일치하는지 확인

const passwordMatch = await bcrypt.compare(password, user.password);

 

 

자료출처

https://docs.nestjs.com/security/encryption-and-hashing

 

'프로그래밍 > TypeScript' 카테고리의 다른 글

[ TS ] DTO object 구현  (0) 2024.08.03
[ TS ] 불변객체 immutable 장점 / 단점 / 구현방법  (0) 2024.07.28
[ TS ] tsconfig.json 의 내용 정리  (0) 2024.06.08
[ TS ] 오버로딩  (0) 2024.05.09
[ TS ] Promise<void> 의미  (0) 2024.05.07

+ Recent posts