TIL - 38 : TDD - Unit Test

TIL - 38 : TDD - Unit Test

TDD - Unit Test

  • Test Runner - 테스트를 실행 후 결과 생성
    • Mocha
  • Assertion - 테스트 조건, 비교를 통한 테스트 로직
    • Chai
    • expect.js
    • better-assert
  • Jest를 이용하면 따로 테스트를 하지 않아도 할 수 있어 좋음

  • npm이 없다면 npm init -y

  • npm i jest -dev 옵션

  • jest --init

  • Jest 홈페이지 참고

  • 파일명.test.js : add라는 파일에 한해서 단위 테스트를 작성하겠다.
const add = require('../add.js'); // node에서는 import가 require

test('테스트이름', () => {
  // 테스트 코드 작성
});
  • jest 를 실행할때 옵셥을 줄 수 있다.
    • "test": "jest --watchAll" 파일이 변경될때마다 테스트 실행
    • "test": "jest --watch" 하나의 파일만 실행
  • Object를 비교하고 싶다면 .toEqual 사용
test('add', () => { // 'add'는 테스트 이름
  // 테스트 코드 작성
  expect(add(3, 5)).toBe(8); // add 라는 함수에 3,5를 넣으면 정확하게 8이 나와야한다.
});
  • test : 테스트
  • expect() : 테스트를 작성할 때 종종 값이 특정 조건을 충족하는지 확인, 예상하다.
  • toBe() : 정확하게 나와야 하는 값
describe('Calculator', () => {
  // 관련된것을 그룹으로 묶음
  it('init with 0', () => {
    const cal = new Calculator();
    expect(cal.value).toBe(0);
  }); //it은 caculator 임

  it('set test', () => {
    const cal = new Calculator();
    cal.set(9);
    expect(cal.value).toBe(9);
  });
});
  • describe : 여러 관련된 것을 그룹화 해서 테스트
  • it : 테스트 이름을 가르키는 네이밍

  • 위와 같이 cal을 만들어 주는 중복 함수는 전역에 한번 선언 할 수도 있지만,
    각각의 테스트는 따로 해주는것이 좋음
  • 그렇지만 코드의 중복을 막아야 하기에 다음과 같이 작성
const cal;
beforeEach(()=>{
  cal = new Calculator();
})
  • beforeEach() : 테스트 코드를 실행 하기 전에 수행
  • afterEach() : 테스트 코드를 실행 한 이후에 수행
  • beforeAll() : 모든 테스트 코드 전에 한번 실행
  • afterAll() : 모든 테스트 코드 후에 한번 실행

Error Test

  • coverage 를 보면 커버하지 않은 라인을 확인할 수 있음
  add(num) {
    if (sum > 100) {
      throw new Error('100 넘을  없습니다.');
    }
    this.value = sum;
  }
  • 이러한 에러를 설정해 놓았다면
  it('addError', () => {
    expect(() => {
      cal.add(150);
    }).toThrow('100 넘을  없습니다.');
  });
  • 이렇게 에러 메세지도 확인이 가능함

Async Test

function fetchProduct(error) {
  if (error === 'error') {
    return Promise.reject('network error');
  }
  return Promise.resolve({ item: 'Milk', price: 200 });
}
  • 이러한 비동기 코드가 있으면
describe('Async', () => {
  it('asyc', () => {
    fetchProduct().then((item) => {   // 아이템을 리턴한다면
      expect(item).toEqual({ item: 'Milk', price: 200 }); 
      // 아이템은 이 오브젝트와 동일한지 검사
    });
  });
});
  • 하지만 이렇게하면 비동기 값이 들어오든 말든 바로 이상 없으면 PASS
  • 이현상을 없애주기 위해서 따로 done이라는 인자를 받아와서 마지막에 호출
  • 간단히 return으로도 가능
describe('Async', () => {
  it('async - done', (done) => {  // done을 인자로 받고
    fetchProduct().then((item) => {
      expect(item).toEqual({ item: 'Milk', price: 200 });
      done();  // done을 마지막에 호출
    });
  });

//or

  it('async - return', () => {  
    return fetchProduct().then((item) => {
      expect(item).toEqual({ item: 'Milk', price: 200 });
    });
  });
});

// await 방식

  it('async - await', async () => {
    const product = await fetchProduct();
    expect(product).toEqual({ item: 'Milk', price: 200 });
  });


  • 하지만 done 방식은 느리기때문에 더빠르고 코드도 깔끔한 return 방식 추천

  • 함수는 Mock 함수를 이용하면 쉽게 테스트 가능

  • 네트워크 상태의 의존하는 코드는 좋지 않음, 이것도 Mock을 이용
    • mock은 흉내 stub은 진짜 같은 진짜 대체 코드
  • 네트워크를 하는게 있다면 따로 클라이언트를 만드는것이 좋다.

© 2022.02 by sunnyfterrain