5 분 소요

문제 상황 예시 - 1

테스트 코드 작성

fn.test.js

const fn = require("./fn");

let num=0

test("0 더하기 1은 1이야", () => {
  num = fn.add(num,1);
  expect(num).toBe(1);
}); // 테스트 성공 // num은 1

test("0 더하기 2는 2야", () => {
  num = fn.add(num,2);
  expect(num).toBe(2);
}); // 테스트 실패 // num은 3

test("0 더하기 3은 3이야", () => {
  num = fn.add(num,3);
  expect(num).toBe(3);
}); // 테스트 실패 // num은 6

test("0 더하기 4는 4야", () => {
  num = fn.add(num,4);
  expect(num).toBe(4);
}); // 테스트 실패 // num은 10

원하는대로 테스트하기 위해서는, 각 테스트를 통과하기 직전에 num을 초기화해주는 작업이 필요하다.

🐤 beforeEach와 afterEach

각 테스트 직전, 직후에 실행된다.

테스트 코드 작성

fn.test.js

const fn = require("./fn");

let num=0

beforeEach(()=>{ 
  // 🌟 각 테스트 직전에 수행
  num=0;
})

test("0 더하기 1은 1이야", () => {
  num = fn.add(num,1);
  expect(num).toBe(1);
}); // 테스트 성공 

test("0 더하기 2는 2야", () => {
  num = fn.add(num,2);
  expect(num).toBe(2);
}); // 테스트 성공 

test("0 더하기 3은 3이야", () => {
  num = fn.add(num,3);
  expect(num).toBe(3);
}); // 테스트 성공 

test("0 더하기 4는 4야", () => {
  num = fn.add(num,4);
  expect(num).toBe(4);
}); // 테스트 성공 

문제 상황 예시 - 2

전후 작업이 시간이 걸리는 일이라면?
예를들어, 테스트 전에 유저 db에 접속해서 유저 정보를 가져오고 테스트 후에는 db connection을 끊는 작업이라면…

함수 작성

fn.js

const fn = {
  connectUserDb:() => {
    return new Promise(res=>{
      setTimeout(()=>{
        res({
          name: "Mike",
          age: 30,
          gender: "male"
        });
      }, 500);
    });
  }, // db로부터 유저 정보를 가져오는데 0.5초 걸린다고 가정
  disconnectDb:() => {
    return new Promise(res=>{
      setTimeout(()=>{
        res();
      }, 500);
    });
  }, // db connection을 끊는데 0.5초 걸린다고 가정

};
module.exports=fn;

테스트 코드 작성

fn.test.js

const fn = require("./fn");

let user;

beforeEach(async()=>{
  user=await fn.connectUserDb(); // 테스트 전에 db에 접속해서 유저의 데이터를 가져오기
})
afterEach(()=>{
  return fn.disconnectDb(); // 테스트 후에 db connection을 끊기
})

// 테스트
test("이름은 Mike", () => {
  expect(user.name).toBe("Mike");
});

test("나이는 30", () => {
  expect(user.age).toBe(30);
});

test("성별은 남성", () => {
  expect(user.gender).toBe("male");
});

매번 테스트마다 db에 접속하고 db 연결을 끊는다면, 테스트가 많아질수록 시간이 너무 오래 걸림.
db는 한번만 연결해서 유저 정보를 가져오고, 모든 테스트를 마친 후 연결 해제을 해제해야한다.
즉, db 연결은 각 테스트 전후가 아니라 최초에 한번 최후에 한번 해주는게 더 나은 방법이다.

🐤 beforeAll과 afterAll

모든 테스트 이전, 이후에 한번씩만 실행된다.

테스트 코드 작성

fn.test.js

const fn = require("./fn");

let user;

beforeAll((async()=>{
  user=await fn.connectUserDb(); // 테스트 전에 db에 접속해서 유저의 데이터를 가져오기
})
afterAll(()=>{
  return fn.disconnectDb(); // 테스트 후에 db connection을 끊기
})

// 테스트는 직전과 동일하다.

이전 코드와 달리, 실행 시간을 줄일 수 있다.

문제 상황 예시 - 3

테스트 코드 내에서 접근해야하는 db의 수가 늘어난다면?

🐤 describe

함수 작성

fn.js

const fn = {
  connectUserDb:() => {
    return new Promise(res=>{
      setTimeout(()=>{
        res({
          name: "Mike",
          age: 30,
          gender: "male"
        });
      }, 500);
    });
  }, // db로부터 유저 정보를 가져오는데 0.5초 걸린다고 가정
  disconnectDb:() => {
    return new Promise(res=>{
      setTimeout(()=>{
        res();
      }, 500);
    });
  }, // db connection을 끊는데 0.5초 걸린다고 가정
  connectCarDb:() => {
    return new Promise(res=>{
      setTimeout(()=>{
        res({
          brand: "bmw",
          name: "z4",
          color: "red"
        });
      }, 500);
    });
  }, // db로부터 자동차 정보를 가져오는데 0.5초 걸린다고 가정
  disconnectCarDb:() => {
    return new Promise(res=>{
      setTimeout(()=>{
        res();
      }, 500);
    });
  }, // db connection을 끊는데 0.5초 걸린다고 가정

};
module.exports=fn;

테스트 코드 작성

fn.test.js

const fn = require("./fn");

describe("User 관련 작업", ()=>{
  let user;

  beforeAll(async()=>{
    user=await fn.connectUserDb(); 
  })
  afterAll(()=>{
    return fn.disconnectDb(); 
  })

  test("이름은 Mike", () => {
    expect(user.name).toBe("Mike");
  });
  test("나이는 30", () => {
    expect(user.age).toBe(30);
  });
  test("성별은 남성", () => {
    expect(user.gender).toBe("male");
  });

});

describe("Car 관련 작업", ()=>{
  let car;

  beforeAll(async()=>{
    car=await fn.connectUserDb(); 
  })
  afterAll(()=>{
    return fn.disconnectDb(); 
  })

  test("브랜드는 bmw", () => {
    expect(car.brand).toBe("bmw");
  });
  test("이름은 z4", () => {
    expect(car.name).toBe("z4");
  });
  test("색은 빨강", () => {
    expect(car.color).toBe("red");
  });

});

describe를 이용해 비슷한 테스트끼리 묶을 수 있다.

describe 내부와 외부의 실행 순서

테스트 코드 작성

fn.test.js

const fn = require("./fn");

// 🌟 describe 외부
beforeAll(() => console.log("외부 beforeAll")); // 1
beforeEach(() => console.log("외부 beforeEach")); // 2, 6
afterAll(() => console.log("외부 afterAll")); // 마지막
afterEach(() => console.log("외부 afterEach")); // 4, 10

test("0 더하기 1은 1이다.", () => {
  console.log("외부 test"); // 3
  expect(fn.add(0,1)).toBe(1); 
});

describe("Car 관련 작업", ()=>{
  // 🌟 describe 내부
  beforeAll(() => console.log("내부 beforeAll")); // 5
  beforeEach(() => console.log("내부 beforeEach")); // 7
  afterAll(() => console.log("내부 afterAll")); // 마지막-1
  afterEach(() => console.log("내부 afterEach")); // 9

  test("0 더하기 1은 1이다.", () => {
    console.log("내부 test"); // 8
    expect(fn.add(0,1)).toBe(1); 
  });
});

밖에 있는 beforeAll이 가장 먼저 실행되고, 밖에 있는 afterAll이 가장 마지막에 실행된다.
🌟 밖에 있는 ~Each는 (밖에서 먼저 실행된 이후에) 안에있는 테스트가 실행되기 전/후에도 실행되므로 두번씩 실행된다.

  • 안에 있는 test가 실행되는 순서
    1. 밖에 있는 beforeEach 🌟
    2. 안에 있는 beforeEach 🌟
    3. 안에 있는 test
  • 안에 있는 test가 실행된 이후에
    1. 안에 있는 test
    2. 안에 있는 afterEach 🌟
    3. 밖에 있는 afterEach 🌟

문제 상황 예시 - 4

테스트가 실패했을 때 (외부 요인때문인지 코드 자체의 문제인지 파악하기 위해서) 실패한 테스트만 다시 실행해보고싶다면?

🐤 test.only

테스트 코드 작성

fn.test.js

const fn = require("./fn");

let num=0;

test("0 더하기 1은 1이다.", () => {
  expect(fn.add(num,1)).toBe(1); 
});
test("0 더하기 2은 2이다.", () => {
  expect(fn.add(num,2)).toBe(2); 
});
test("0 더하기 3은 3이다.", () => {
  expect(fn.add(num,3)).toBe(3); 
});
test("0 더하기 4은 4이다.", () => {
  expect(fn.add(num,4)).toBe(4); 
  num=10
});
test.only("0 더하기 5은 10이다.", () => { // 해당 테스트 코드만 실행
  expect(fn.add(num,5)).toBe(10); // 테스트 실패
});

코드 자체의 문제

only로 돌렸을 때에도 실패한다면? 코드 자체의 문제
실패한 테스트 코드에서 toBe에 10이 아니라 5가 들어가야한다. 따라서 아래와 같이 코드를 수정한다.

test.only("0 더하기 5은 5이다.", () => { 
  expect(fn.add(num,5)).toBe(5); // 테스트 성공
});

코드 변경 이후 only로 돌렸을 때에는 성공하였다.

외부 요인의 문제

하지만 only를 떼고 돌렸을 때에는 마찬가지로 실패한다면? 외부 요인의 문제
4번째 테스트에서 num에 10을 대입한게 문제이다. 따라서 아래와 같이 4번째 테스트 코드를 수정한다.

test("0 더하기 4은 4이다.", () => {
  expect(fn.add(num,4)).toBe(4); 
});
test("0 더하기 5은 10이다.", () => { 
  expect(fn.add(num,5)).toBe(10); 
});

이제 only를 떼고 돌릴 때에도 성공한다.

🐤 test.skip

예제에서는 단순한 코드이기때문에 4번째 테스트의 코드를 바로 변경할 수 있었지만, 복잡한 코드라 당장 변경할 수 없다면?

test.skip("0 더하기 4은 4이다.", () => { // 해당 테스트는 건너뛰고 실행
  expect(fn.add(num,4)).toBe(4); 
  num=10
});

skip 대신에 해당 테스트에 주석처리를 해도 된다.

참고

코딩앙마



💛 개인 공부 기록용 블로그입니다. 👻

맨 위로 이동하기