본문으로 바로가기

[Jest] 4. SuperMarket 테스트 코드 작성 및 에러 처리

이전 게시글 3. Matchers & SuperMarket 테스트 코드 작성 준비에서 확인한 SuperMarket Class의 테스트 코드를 작성해봅시다. 그리고 시작하기 전 미리 말씀드리면 package.json에 script를 아래와 같이 수정해주세요.

"scripts": {
  "test": "jest --watch --verbose"
}

SuperMarket 테스트 코드 작성하기

이전 게시글에서 확인한 SuperMarket Class의 테스트 코드를 한번 작성해보셨나요? 안해보셨다면 지금이라도 해보시고 확인하시는 것을 추천드립니다. 우선 저 같은 경우는 아래와 같이 작성하였습니다.

const SuperMarket = require("../superMarket.js");

describe("SuperMarket", () => {
  let superMarket = null;

  beforeEach(() => {
    superMarket = new SuperMarket();
  });

  describe("초기 금액 확인", () => {
    it("초기 잔고는 5000원입니다", () => {
      expect(superMarket.balance).toBe(5000);
    });

    it("snack 금액은 2000원입니다", () => {
      expect(superMarket.snack).toBe(2000);
    });

    it("chocolate 금액은 1000원입니다", () => {
      expect(superMarket.chocolate).toBe(1000);
    });

    it("icecream 금액은 3000원입니다", () => {
      expect(superMarket.icecream).toBe(3000);
    });

    it("gum 금액은 500원입니다", () => {
      expect(superMarket.gum).toBe(500);
    });
  });

  describe("구매 확인", () => {
    it("2000원 지불 / snack 1개 구매 / 거스름돈 : 0원 / 잔고 : 5000원", () => {
      expect(superMarket.buy("snack", 1, 2000)).toBe(0);
      expect(superMarket.getItemPrice("balance")).toBe(5000);
    });

    it("2000원 지불 / chocolate 2개 구매 / 거스름돈 : 0원 / 잔고 : 5000원", () => {
      expect(superMarket.buy("chocolate", 2, 2000)).toBe(0);
      expect(superMarket.getItemPrice("balance")).toBe(5000);
    });

    it("3500원 지불 / icecream 1개 구매 / 거스름돈 : 500원 / 잔고 : 5500원", () => {
      expect(superMarket.buy("icecream", 1, 3500)).toBe(500);
      expect(superMarket.getItemPrice("balance")).toBe(5500);
    });

    it("1400원 지불 / gum 3개 구매 / 거스름돈 : -1원 / 잔고 : 5000원", () => {
      expect(superMarket.buy("gum", 3, 1400)).toBe(-1);
      expect(superMarket.getItemPrice("balance")).toBe(5000);
    });
  });
});

이해가 되실까요? 제가 작성한 코드에 대해 약간의 설명을 추가해보겠습니다.

- describe

describe비슷한 맥락(?)끼리 묶어주는 역할을 합니다. 저는 SuperMarket을 기준으로 describe를 하였습니다. 그리고 추가로 그 안에서 초기 금액 확인, 구매 확인으로 또 나누었습니다. 이렇게 나누게 되면 이후 테스트 코드 실행 시 결과창이 깔끔해 진 것을 볼 수 있습니다. 다시 말하면 문서화 하기 좋습니다. 나중에 타 개발자가 내가 작성한 테스트 코드만 보고도 아! 해당 코드가 무엇을 하는 것이구나 라는 것을 알 수 있게 됩니다. 진짜 그런 지 아래 결과를 확인해봅시다.

테스트 결과가 한눈에 보아도 문서화가 되어 있죠? 이렇게 문서화 작업을 따라하지 않아도 되도록 테스트 코드를 잘 작성해주는 것이 중요합니다.

- beforeEach

저번 게시글에서 beforeEach에 대해 잠깐 언급하였는데요. 테스트 작성 시 필요해보여서 미리 언급하였습니다. beforeEach각각의 테스트가 실행되기 전 실행하는 함수입니다. 모든 테스트는 독립적이어야 합니다. 다시 말하면 A 테스트가 B 테스트에 영향을 끼치면 안된다는 것이죠. 따라서 혹시 모를 문제를 예방하기 위해 각각의 테스트 전 SuperMarket의 객체를 생성해준 것입니다.

SuperMarket Class 및 테스트 코드 개선하기

위 SuperMarket Class와 테스트 코드를 개선해봅시다. 1가지만 개선해보려고 하는데요. buy 함수에서 구매하지 못 하는 경우 -1을 return 해줍니다. 그러나 사실 이 경우 error가 발생하는 것이 맞겠죠? 아래처럼 buy 함수를 수정해줍시다.

buy(item, count, paidAmount) {
  const totalPrice = this.getItemPrice(item) * count;

  if (paidAmount >= totalPrice) {
    this.balance += paidAmount - totalPrice;
    return paidAmount - totalPrice;
  } else {
    return -1;
  }
}

buy(item, count, paidAmount) {
  const totalPrice = this.getItemPrice(item) * count;

  if (paidAmount >= totalPrice) {
    this.balance += paidAmount - totalPrice;
    return paidAmount - totalPrice;
  } else {
    throw new Error("금액이 부족합니다.");
  }
}

그럼 테스트 결과가 아래처럼 실패로 표시됩니다.

너무나 당연한 결과입니다. 우리가 superMarket의 buy 함수를 수정했으니 test code도 거기에 맞게 수정을 해주어야겠죠? test code를 아래와 같이 수정해줍니다.

it("1400원 지불 / gum 3개 구매 / 거스름돈 : -1원 / 잔고 : 5000원", () => {
  expect(superMarket.buy("gum", 3, 1400)).toBe(-1);
  expect(superMarket.getItemPrice("balance")).toBe(5000);
});

it("1400원 지불 / gum 3개 구매 / 에러 처리 / 잔고 : 5000원", () => {
  expect(() => superMarket.buy("gum", 3, 1400)).toThrow(
    "금액이 부족합니다."
  );
  expect(superMarket.getItemPrice("balance")).toBe(5000);
});

그럼 모든 test가 정상적으로 통과하게 됩니다. 아래 결과를 확인해봅시다.

그럼 어떻게 에러가 발상하는 것을 처리하는 test code를 작성할 수 있을까요? 위에서 수정 후 코드를 보았듯이 에러 test code를 작성하는 방법은 아래와 같습니다.

expect(() => test_코드_함수()).toThrow(에러_메시지);

위와 같이 에러 테스트 코드를 작성하시면 됩니다.

참고자료

마지막

해당 내용은 틀릴 수도 있습니다. 틀린 내용이 있으면 조언 부탁드립니다.

반응형