간단하고 안정적인 테스트를 위해 내가 따르는 6가지 규칙

테스트를 작성할 때 무엇이 ​​작동하는지 알아내려고 노력하고 실패하는 데 몇 년이 걸렸습니다. 어떤 종류의 테스트를 작성하든 항상 따르는 6가지 규칙이 있습니다.

AAA 패턴 따르기



깨끗한 단위 테스트는 AAA 패턴을 따릅니다.

  • 정렬: 테스트 시나리오 설정

  • 실행: 비즈니스 로직 실행

  • 주장: 약간의 기대를 하십시오
  • .

    이것은 간단한 테스트의 성배입니다.

    테스트당 단일 개념



    각 단위 테스트에서 단일 개념을 테스트합니다. AAA 패턴을 따른다면 자연스럽게 느껴질 것입니다.

    종종 단일 단위 테스트에서 다양한 개념을 다루는 테스트를 봅니다. 그것은 코드 냄새입니다. 이러한 테스트를 여러 테스트로 분할하는 것이 좋습니다. 각 테스트는 고유한 테스트입니다.

    Rule of thumb - if there is an act after your assert, you should consider to splitting it out into two separate tests.



    테스트를 이해하기 쉽고 수정하기가 더 쉽습니다.

    // Bad - mixing two concepts
    it('should add new item into cart', () => {
      let cart = new Cart()
      cart.add(new Item('Shoes')) // <-- // Testing adding item into cart
      expect(cart.size).toBe(1);
      cart.removeAllItems(); // <-- Testing removing all items from cart
      expect(cart.size).toBe(0);
    });
    
    // Better - split it up
    it('should add new item into cart', () => {
      let cart = new Cart();
      cart.add(new Item('Shoes');
      expect(cart.size).toBe(1);
    });
    
    it('should be possible to remove all items from cart', () => {
      let cart = new Cart([new Item()]);
      cart.removeAllItems();
      expect(cart.size).toBe(0);
    });
    


    테스트에서 논리를 피하십시오



    테스트 코드에서 if , else , switch 또는 ternary operator 을 피하십시오.

    The moment you use any of the control flow statements - you added logic to your test and now you need a test for your test.



    이것은 종종 다른 입력에 대해 약간 다른 동작을 예상하는 매개변수화된 테스트에서 발생하지만 누군가가 불안정한 테스트로 인한 실패를 피하고자 하는 테스트에서도 발생합니다.

    이와 같은 경우에는 항상 분할하고 평평하고 단순하게 유지하는 것이 좋습니다.

    // Bad
    it("should have focus when clicked", () => {
      render(<Input />)
      const input = screen.getByRole("input")
    
      // this null check is pointless
      if (input !== null) {
        click(input)
        expect(input).toHaveFocus()
      }
    })
    
    // Better
    it("should have focus when clicked", () => {
      render(<Input />)
      click(screen.getByRole("input"))
      expect(screen.getByRole("input")).toHaveFocus()
    })
    


    단순성을 위해 최적화



    좋은 테스트는 짧고 평평하며 간단하고 즐겁게 작업할 수 있습니다. 테스트를 보면 즉시 의도를 파악해야 합니다.

    테스트를 중첩하지 마십시오. 불필요한 복잡성을 추가합니다. 각 중첩 수준은 코드에 여분cognitive complexity을 추가합니다.

    반복을 피하기 위해 일반적인 설정 코드를 고정 장치로 리팩터링합니다.

    공개 API만



    테스트에서 사용자가 할 수 없는 작업을 수행하는 경우 구현 세부 정보를 테스트할 가능성이 큽니다.

    이것은 코드 냄새입니다. 기본 구현이 변경되면 테스트가 중단됩니다.

    사용자가 사용할 수 있는 API만 테스트하십시오.

    TDD를 사용하여 커버리지 확대



    TDD를 사용할 때 10/10번, 코드 커버리지가 80% 이상 올라갑니다.

    행복한 경로로 시작하세요. 코드가 기본 사용 사례에서 작동하는지 확인하세요.

    불행한 경로로 계속 진행 - 오류 조건, 예기치 않은 입력 또는 기타 극단적인 경우를 다룹니다.

    사소한 원라이너, 게터 및 세터 테스트를 건너뛸 수 있습니다.

    이것으로 80% 커버리지 마크에 쉽게 도달해야 합니다.

    Don’t obsess about code coverage - it only tells you what lines were executed, not if they work as intended. Focus more on writing meaningful tests.



    그게 다야



    이 몇 가지 규칙을 사용하면 모든 사람이 이해할 수 있고 즐겁게 작업할 수 있는 테스트를 작성할 수 있습니다.

    준수해야 하는 다른 규칙이 있다면 알려주십시오. 그 이유는 무엇입니까?

    좋은 웹페이지 즐겨찾기