[FE] 기능 테스트와 TDD 및 테스트 코드 작성 가이드라인

JunSeok·2024년 7월 29일
0

테스트

목록 보기
1/1
post-thumbnail

썸네일 출처

테스트 코드의 목적 및 종류

테스트란?

테스트는 우리가 작성한 코드가 예상대로 작동하는지 확인하는 과정을 의미한다.

가장 기본적이고 확실한 테스트 방법은 기능을 직접 사용하여 기능이 의도한대로 제대로 작동하는지 확인하는 것이다.
그러나 코드가 수정될 때마다 직접 테스트를 수행하는 것은 시간이 많이 걸리고, 실수할 가능성이 있다.

그래서 테스트 코드를 작성하여 테스트 과정을 자동화한다.

프론트엔드에서의 테스트

프론트엔드 테스트는 일반적인 테스트와 다르다.

비즈니스 로직을 담은 함수의 입출력(I/O)을 검증하거나 세부 구조 및 동작을 검증하는 것과 달리, 프론트엔드 테스트는 사용자 경험에 초점을 맞춘다.

즉 사용자가 발생시키는 이벤트(click, scroll, focus 등)에 대한 화면의 반응을 확인하는 과정이다. 이를 통해 적절한 화면이 출력되었는지 테스트한다.

이벤트 트리거는 react testing library와 같은 도구를 사용해 쉽게 수행할 수 있지만, 출력된 화면을 확인하는 것은 간단하지 않다.
사람이 직접 확인할 때는 화면이 기대와 동일한지 눈으로 확인하지만, 컴퓨터는 픽셀 단위로 비교해야 하며 이는 많은 시간을 소요하고 거짓 음성을 발생시킬 수 있다.

거짓 음성(false nagetive)이란 실제 결과는 성공했지만 테스트는 실패한 경우이다.
이는 사람의 눈에는 원하는 화면이 출력되었지만 픽셀에서 차이가 발생하기 때문에 발생한다.

따라서 픽셀 비교 대신 기능의 중요한 내용을 비교 단위로 삼는 방식이 존재한다.
예를 들어, 버튼을 누르면 특정 텍스트가 추가되는지 확인하는 것이다.
이는 픽셀 비교 방식보다는 정확성이 떨어질 수 있지만, 시간 소요와 거짓음성 문제를 해결할 수 있다.

픽셀 비교는 시각적 테스트, 기능 비교는 기능적 테스트라고 한다.

시각적 테스트에는 스냅샷 테스트시각 회귀 테스트가 있고,
기능적 테스트에는 단위 테스트, 통합 테스트, E2E 테스트가 있다.

테스트 코드의 목적

자동화된 검증

  • 신규 기능 개발 시, 이를 검증하기 위한 QA 과정에 많은 시간과 노력이 소요된다.
  • 또한 기존 코드와 연관된 새로운 기능을 개발하거나 리팩토링할 때, 테스트 코드가 없으면 반복적인 QA 과정을 거쳐야 한다.
  • 서비스의 안정성을 보장할 수 있는 테스트 코드가 있다면 QA 과정에서 에러 발생 확률이 줄어들고, 자유롭게 리팩토링하거나 새로운 기능을 추가할 수 있다.

제품에 대한 신뢰성 확보

테스트 코드를 작성하기 전에 지원하는 기능을 명확히 정의함으로써 사용자가 사용하는 기능이 제대로 작동할 것이라는 신뢰성이 생긴다.

TDD를 제안한 켄트 벡은 테스트 코드 작성을 불안함을 지루함으로 바꾸는 과정이라 했다.

협업 효율성 증가

애플리케이션이 지원하는 기능을 명확히 정의하여 테스트 코드를 정의하기 때문에 팀원이 어떤 기능을 개발하고 테스트하는지 한 눈에 확인할 수 있다.
테스트 코드 파일 자체가 잘 작성된 개발 문서로 활용될 수 있다. 이는 협업에 있어 소통의 안정성을 더해준다.

테스트 코드의 종류

단위 테스트(Unit test)

  • 단위테스트란 애플리케이션 안에 있는 개별적인 코드 단위를 테스트하는 방식이다.

  • 보통 함수, 리액트 컴포넌트, 커스텀 훅을 테스트한다.

  • 다른 코드의 유닛과 상호작용하는 것을 테스트하지 않는다.

  • 입력값만을 이용해 출력값을 결정짓는 순수함수이면 좋다.
    - 순수함수의 경우 오로지 입력값만으로 출력값이 정해지기 때문에 외부 상태값을 가짜로 만들어내지 않아도 되어서 테스트하기 쉽고, 가짜 값을 만들지 않다보니 가짜 값이 유효한 값인지 신경쓰지 않아도 되기 때문이다.
    - 외부에 의존성이 있다면 의존성을 mocking(가짜로 대체)한다. 외부 의존성의 실패가 아닌 특정 유닛의 실패임을 단정하기 위함
    - 격리된 unit test에서 실패를 쉽고 정확하게 파악할 수 있다.

  • 근데 이는 사용자가 소프트웨어와 상호작용하는 방식과는 거리가 멀다.

  • 또한 리팩토링하는 과정에서 실패할 수 있다.
    => 동작은 그대로이나 구현의 변경이 테스트 실패의 원인이 될 수 있다.

  • 도메인과 관련이 높고, 의존성이 낮으면서 로직이 복잡한 함수가 최고의 대상이다.

  • 지나치게 복잡한 코드는 리팩토링의 신호이다.

  • 컨트롤러와 같이 외부의존성만을 다루는 코드는 테스트의 우선순위가 낮다.

unit test 예시
// 컴포넌트 테스트 예시
const TextField = ({ title, onChange }) => {
  return (
    <div>
      <label htmlFor={title}>{title}</label>
      <input id={title} onChange={onChange}></input>
    </div>
  )
}

// 테스트
test("label을 클릭하면 input이 foucus 됩니다", async () => {
  const title = "일련번호"
  const onChange = jest.fn()

  render(<TextField title="일련번호" onChange={onChange} />)

  userEvent.click(screen.getByText("일련번호"))

  expect(screen.getByLabelText(title)).toHaveFocus()
})

test("input에 값을 넣은 만큼 onChange 핸들러가 호출 됩니다", async () => {
  const title = "일련번호"
  const onChange = jest.fn()

  render(<TextField title={title} onChange={onChange} />)

  userEvent.click(screen.getByText(title))
  userEvent.type(screen.getByLabelText(title), "hello")

  expect(onChange).toHaveBeenCalledTimes(5)
})

// 커스텀 훅
export const useCarousel = (initialIndex: number, carouselLength: number) => {
  const [step, setStep] = useState(
    initialIndex < carouselLength ? initialIndex : 0
  )

  const prevStep = () => {
    if (step === 0) return setStep(carouselLength - 1)
    setStep(step - 1)
  }

  const nextStep = () => {
    if (step === carouselLength - 1) return setStep(0)
    setStep(step + 1)
  }

  return { step, prevStep, nextStep }
}

// 테스트
it("초기값이 캐러샐 길이보다 긴 경우 첫번째 step을 0으로 설정한다", () => {
  const { result } = renderHook(() => useCarousel(5, 3))

  expect(result.current.step).toBe(0)
})

})

통합 테스트(Integration test)

  • 통합 테스트는 여러 유닛을 통합하여 함께 동작하는 방식을 테스트하는 것을 의미한다.
  • 유닛(컴포넌트)을 통합한 결과는 페이지가 될 수도 있고 페이지 내의 특정 영역이 될 수도 있다.
  • 통합테스트가 시간이 좀 오래걸리더라도 단위테스트보다 어플리케이션의 신뢰성을 확보하는데 훨씬 효과적이다.
  • 통합 테스트 단계에서는 실제 Api를 사용하게 되면 시간이 오래 걸리는것 뿐만 아니라 테스트가 백엔드에 의존성을 가져서 백엔드의 문제 때문에 실패하는 상황이 발생 할 수 있다. Api의 경우 테스트를 위해 모킹을 하는것이 좋다.
  • 통합테스트를 위한 API 모킹시에는 msw라는 라이브러리가 유용하다.
Integration test 예시
it("검색어 입력후 검색 버튼을 클릭하면 검색 결과를 보여준다.", async () => {
  render(<App />)

  const inputBox = screen.getByRole("textbox")
  const searchButton = screen.getByRole("button")

  act(() => {
    userEvent.type(inputBox, "테스트")
    userEvent.click(searchButton)
  })

  await waitFor(() => {
    expect(screen.getAllByText("테스트", { exact: false }).length).toBe(20)
  })
})

it("검색어 입력후 검색 버튼을 클릭하였을때 결과가 없을 경우 결과가 없음을 보여준다", async () => {
  render(<App />)

  const inputBox = screen.getByRole("textbox")
  const searchButton = screen.getByRole("button")

  act(() => {
    userEvent.type(inputBox, "검색 결과 없는 검색어")
    userEvent.click(searchButton)
  })

  await waitFor(() => {
    expect(screen.getByText("검색 결과가 없습니다")).toBeInTheDocument()
  })
})

E2E 테스트

  • E2E 테스트는 End To End 테스트의 약자로 cypress, playwrite와 같은 E2E 테스트 도구를 이용하여 애플리케이션의 흐름을 처음부터 끝까지 테스트하여 애플리케이션의 무결성을 검증하는 테스트를 의미한다.
  • 실제 브라우저 환경에서 실제 api를 사용하기 때문에 테스트 하는데 매우 오랜 시간이 걸린다. 보통 배포 직전에 테스트한다.
E2E 테스트 예시(Cypress)
it("사용자가 로그인 페이지에 진입해 아이디 비밀번호입력후 엔터키를 눌러 로그인에 성공하는경우 홈으로 이동해 유저 프로필을 확인한다", function () {
  // destructuring assignment of the this.currentUser object
  const username = "test"

  const password = "1234"

  // 로그인 페이지 진입
  cy.visit("/login")

  // 아이디 입력 input에 username 입력
  cy.get("input[name=username]").type(username)

  // 패스워드 입력 input에 password 입력 및 enter 입력
  cy.get("input[name=password]").type(`${password}{enter}`)

  // home으로 리다이렉션
  cy.url().should("include", "/home")

  // home에 username이 있는지 확인
  cy.get("h1").should("contain", username)
})

시각적 테스트

  • 앞서 설명한 기능적 테스트 만으로 우리가 만든 애플리케이션이 정상 동작함을 보장할 수 없다.
  • 기능은 동작할지 몰라도 글자가 너무 작아서 보이지 않거나 혹은 색상이 의도와 달라 눈에 잘 안 들어올 수 있다.
  • 이를 위해 프론트엔드에서는 시각적 테스트를 수행해야 한다.
  • 시각적 테스트에는 크게 스냅샷 테스트시각적 회귀 테스트가 있다.
스냅샷 테스트
  • 스냅샷이란 특정 시점의 컴포넌트 혹은 함수의 결과를 직렬화하여 텍스트 형태로 저장해두고 매 테스트 마다 변경되었는지를 확인하여 변경이 실제 의도한것인지 확인하는 것이다.
  • 스냅샷 테스트를 사용하여 간단하게 컴포넌트의 출력을 검증할 수 있지만 html 속성이 아닌 css 속성이 달라진경우를 잡아낼수 없고, 스냅샷이 html태그로 구성된 텍스트 데이터를 보여주기 때문에 비교에 실패하더라도 실제 의도한 출력이 맞는지 확인하기 어려우며, 스냅샷 실패시 테스트를 성공상태로 만들기 매우 쉬워 실제 의도한 출력이 아니더라도 기대하는 테스트 결과로 저장되면 이후 거짓 음성이 나오게되어 테스트에대한 신뢰도가 떨어질 수 있다.
시각적 회귀 테스트
  • 앞서 설명한 스냅샷 테스트의 상위 버전이라고 부를수 있으면서 실제 프론트엔드에서 테스트와 가장 유사한 테스트 이다.
  • 많은 비용이 드는 테스트 이므로 주로 CI환경에 테스트 플로우를 세팅해두어 사용한다.
  • 플로우는 다음과 같은데, 매 커밋시마다 테스트 대상의 화면과 저장된 화면을 비교하여 차이가 있는지 파악하고, 차이가 존재한다면 사용자의 approve 혹은 코드 수정을 통해 테스트를 통과시키는 방식이다.
  • 시각적 회귀 테스트는 여러 도구로 수행할수 있다. storybook과 chromatic의 조합으로 사용 하는 방식이 있다.
  • 시각적 회귀 테스트를 수행하지 않더라도 storybook을 이용하면 개별 컴포넌트를 시각적으로 확인하기 용이하기 때문에 만약 시각적 회귀 테스트 비용이 부담된다면 storybook을 이용해 매 코드 변경시 컴포넌트의 UI를 확인하거나 혹은 개발시 UI를 확인하면서 작업할때 용이하다.

기능 테스트(Functional test)

  • 위에서 언급한 테스트 종류와 별개로 기능 테스트라는 것이 있다.
  • 우리가 지향해야 하는 테스트가 바로 기능 테스트이다.
  • 기능 테스트는 소프트웨어의 특정 기능이 명세서나 요구사항에 맞게 동작하는지를 확인한다.
  • 소프트웨어가 실제 사용자 경험과 유사하게 작동하는지를 테스트하여, 사용자와 소프트웨어의 상호작용 방식을 평가한다.
  • 코드가 아닌 실제 사용자의 소프트웨어 사용 경험을 중점으로 테스트한다.
  • 코드가 리팩토링되더라도 동작이 동일하면 테스트는 통과한다.
  • 테스트가 통과하면 사용자 경험상 문제가 없음을 보장한다.
  • 장점: 사용자의 실제 소프트웨어 사용 방식을 반영하기 때문에, 사용자의 입장에서 소프트웨어가 제대로 동작하는지를 확인할 수 있다.
  • 단점: 테스트가 실패할 경우 디버깅이 어려울 수 있다.
  • RTL 철학과의 유사성: 기능 테스트는 내부 코드 구현보다는 사용자의 소프트웨어 사용을 테스트하는 것을 중시합니다. 이는 테스트 도구인 RTL(React Testing Library)의 철학과 일치한다.

Kent C. Dodds

  • 신뢰성 확보
    - 사용자가 애플리케이션을 사용할 때 제대로 작동할 것이라는 신뢰성을 위해 테스트를 작성한다.
    - 테스트는 소프트웨어 사용 방식과 유사할수록 신뢰도가 높아진다.
    - 코드를 테스트하기보다는 서비스가 지원하는 기능인 Use Case를 테스트해야 한다.
    - 구현 세부 사항을 테스트하면 딴 길로 새기 쉽다.
    - 즉 코드 내부의 동작 방식을 테스트하는 것이 아니라 코드가 사용자에게 제공하는 기능을 테스트하는 것에 초점을 맞춰야 한다.
    - unit test 든 integration test 든 테스트의 종류와 상관없다.
  • 테스트 대상 선정 방법
    - 테스트 코드 커버리지는 크게 신경써야 할 지표가 아니다.
    - 대신 use case 커버리지가 중요하다. 이는 우리가 수동으로 작성해야 한다.
    - 테스트 코드 작성하기 전에 모든 use case를 생각해야 한다.
    - 즉 애플리케이션이 지원하는 기능의 목록을 작성하고 이 기준에 따라 우선순위를 정하는 것이 좋다.
    - 애플리케이션에서 에러가 발생하면 큰일이 나는 부분부터 테스트 코드를 우선해야 한다.
    - 회의를 통해 모든 프론트엔드 개발자들이 테스트의 중요성을 이해하고 우선순위를 확립하도록 한다.
    - use case 커버리지를 작성하고 이를 기반으로 테스트 코드를 작성하고, 구현 코드를 작성한다. 이 과정으로 인해 테스트 파일 자체가 기능 명세서가 될 수 있다.
    - 즉 코드를 테스트하는 것이 아니라 use case를 테스트해야 한다.
  • 리팩토링
    - 리팩터링은 기존에 의도한 동작은 유지하면서 구현만 변하는 것을 의미한다.
    - 구현 세부사항 테스트에 집중하면 false positive, false negative가 발생할 수 있다.
    - false negative는 동작은 성공하지만 테스트 코드가 실패하는 경우이다.
    - 리팩터링 시 false negative를 줄 수 있다.
    - 즉 기존 동작은 변경하지 않으면서 구현만 변경을 했음에도 불구하고 테스트가 실패한다.
    - 그 결과 유지 관리가 어렵고 성가신 테스트 코드가 많이 생성된다.
    - false positive는 테스트는 성공했지만, 원래는 실패했어야 한다는 뜻이다.
    - 이를 방지하기 위해 구현 세부 사항을 테스트하지 않도록 API를 제한하면서 모든 테스트를 다시 작성해야 한다.
    - RTL을 사용하면 그의 철학으로 인해 구현 세부 사항을 테스트하는 것이 아니라 기능 자체를 테스트할 수 있다.

TDD와 테스트 코드 작성 가이드라인

테스트 주도 개발(TDD)

TDD란 Test Driven Development의 약자로 켄트 벡이 1999년 익스트림 프로그래밍의 일부로 제안하며 널리 알려졌다.
동작하는 코드 작성 이전에 테스트를 먼저 작성하고 그 테스트를 통과하는 코드를 작성함으로써 테스트된 동작하는 코드를 얻는 개발 방법이다.

흐름

  • 테스트 코드를 작성한다. (빨간 막대)
    - 구현하려는 동작을 설명하는 테스트 코드를 작성한다.
    - 동작을 구현하는 코드는 아직 작성하지 않았으니 당연히 실패해야 한다.
  • 실행 가능하게 만든다. (초록 막대)
  • 올바르게 만든다. (리팩토링)

TDD와 use case 커버리지 작성

  • Kent C. Dodds이 말한 테스트 코드 작성 이전 use case 커버리지 작성은 TDD와 궁합이 잘 맞는다.
  • use case 커버리지 작성 이후, 테스트 코드를 작성하고 구현 코드를 작성한다.

테스트 코드 작성 프로세스

  1. 개발 회의를 통해 애플리케이션 기능의 우선순위를 정한다.
  2. 기능을 배정받은 개발자는 각 기능의 use case coverage를 작성한다.
  3. 각 use case마다 테스트 코드를 작성한다.
  4. 테스트 코드에 맞게 구현 코드를 작성한다.
  5. 리팩토링한다.

가이드라인

  • 제목을 알아보기 쉽게 설정한다. 다른 개발자가 보고 즉시 의미를 알아챌 수 있어야 한다.
  • 하나의 테스트에는 하나의 기능만 테스트한다.
  • 가독성을 위해 AAA 패턴을 지킨다.
  • 내부 구현을 테스트하는 것이 아니라 사용자가 실제로 사용하는 방식으로 소프트웨어를 테스트하는 것이 목표이다.
  • 단위 테스트(Unit Test), 통합 테스트(Integration Test), E2E 테스트 등 여러 테스트의 종류가 있지만 이들 모든 테스트의 목적은 특정 기능이 올바르게 작동하는지를 검증하는 것이다.
  • 보통 통합 테스트를 먼저 작성하고, 단위 테스트나 E2E 테스트를 작성하는 방식으로 한다.
  • 새로운 기능 추가 또는 리팩토링시 코드 구현이 변경되어도 의도된 동작이 그대로 수행되어 테스트가 통과되어야 한다.
  • 테스트 코드는 중복이 다소 발생하더라도 직관적이고 명확하게 이해되도록 테스트 코드를 작성해야 한다.
  • 100% Code Coverage를 목표로 삼지 말아야 한다. 그럴 가치가 없다.
  • 테스트 코드는 완벽하지 않아도 된다.
  • E2E 테스트는 비용이 많이 들기 때문에 비즈니스적으로 중요한 영역에 적용한다.
  • 시각적 테스트는 시각적 요소가 중요한 페이지에만 적용한다.
  • 모킹이 많은 것은 이상적이지 않다.
  • 스냅샷 테스트보다는 시각적 회귀 테스트를 사용하는 것이 좋다.
  • 정기적인 코드리뷰를 통해 테스트 코드에 대한 피드백을 제공하고 개선점을 논의한다. 이를 통해 모든 팀원이 테스트 코드를 작성하는 문화가 자리잡음으로써 전체적인 코드 품질과 안정성 향상을 도모할 수 있다.

AAA 패턴

  • Arrange
    - 테스트가 목표로 하는 시나리오에 대한 시스템을 제공하기 위한 모든 설정 코드 작성
  • Act
    - 테스트 실행, 필요시 결과 저장
    - 테스트 대상 시스템 메서드 호출하고 결과, 출력값을 저장.
  • Assert
    - 받은 예상값이 충족하는지 검증

사용 테스트 도구

React Testing Library

https://testing-library.com/docs/react-testing-library/intro/

가상 DOM 제공

브라우저 없이 테스트하기 위해 시뮬레이션된 DOM을 생성하고, 이를 활용하여 DOM과 상호작용할 수 있는 유틸리티를 제공한다.

렌더링 이후, react testing library의 전역 객체 screen을 통해 시뮬레이션된 DOM에 액세스할 수 있다.

사용자 중심의 테스트

사용자가 실제로 소프트웨어를 사용하는 방식과 동일하게 테스트할 수 있도록 돕는다.

테스트에서 사용자가 버튼 클릭과 같은 작업을 하고 버튼을 클릭한 후 DOM이 어떤 모습인지 확인할 수 있다.

모범 사례 지향

구현 세부 정보보다는 구성 요소의 동작을 테스트하는 데 중점을 두며, HTML 태그를 최대한 활용하여 테스트한다.

RTL이 공식문서에서 강조하는 원칙은 다음과 같다.

"테스트 코드를 작성하고 테스트를 수행함에 있어서 테스트가 서비스의 사용 방식과 유사할수록 더 많은 신뢰를 얻을 수 있다"

이는 즉 우리가 추구하는 테스트 목표와 동일하다.

RTL이 요소를 찾는 방법
  1. 접근성 높은 메서드
    • getByRole: 접근성 트리에 노출된 모든 요소를 조회하며, 가장 접근성과 사용자 경험을 고려하는 메서드이다.
    • getByLabelText: form 필드 내부 요소들을 각자의 label로 찾는다.
    • getByPlaceholderText: placeholder를 대체자로 사용한다.
    • getByText: 텍스트로 요소를 찾는다.
    • getByDisplayValue: form 내부에서 이미 값이 입력된 요소를 찾는다.
  2. ARIA 관련 props 사용 메서드
    • getByAltText: 요소 내에 alt 속성을 조회한다.
    • getByTitle: Title 속성을 조회한다.
  3. Test-id
    • getByTestId: 위의 방법이 모두 불가할 때 최후의 수단으로 사용한다.

Vitest

https://vitest.dev/
테스트를 찾고, 실행하며, 통과 여부를 결정하는 도구이다.
Jest와 문법이 동일하고 빌드 도구인 vite와 호환성이 좋다.
RTL은 시뮬레이션된 DOM을 리턴하며, Vitest와 같은 테스트 러너를 사용하여 테스트를 실행한다.

MSW(Mocking Service Worker)

MSW 공식 문서
MSW는 브라우저 및 Node.js 환경에서 사용 가능한 API 모킹 라이브러리이다.

사용 배경
  • 프로덕션 코드에서 백엔드 API 개발 속도와 프론트엔드 개발 속도가 맞지 않아 프론트엔드 개발 진행에 어려움이 있을 수 있다.
  • 테스트 코드를 작성하고 실행할 때 실제 API 요청을 할 경우 비용, 속도 및 의존성 문제가 발생할 수 있다.
  • MSW 라이브러리를 이용하면 Mock 서버를 구축하지 않아도 API를 네트워크 수준에서 Mocking 할 수 있다.
  • MSW는 네트워크 요청 과정에서 Request에 대한 Mocking이 가능한 라이브러리이며 네트워크 요청을 가로채서 모의 응답을 보내주는 역할을 한다.
특징
  • 독립성
    라이브러리나 프레임워크에 영향을 받지 않게 설계되었다.
    별도의 플러그인 설치 없이 모든 브라우저와 Node.js 환경에서 사용 가능하다.
  • 실제 네트워크 요청 모킹
    fetch와 같이 네트워크 요청 함수를 mocking하는 것에 그치지 않고 실제로 보내진 네트워크 요청을 가로챈다.
  • 재사용성
    프로덕션 코드 및 테스트 코드에서 모두 사용 가능하다.
원리

브라우저에서는 브라우저에서 제공하는 Service Worker를 이용해서 mocking 한다.
(Node.js 환경에서는 http, XMLHttpRequest와 같은 네트워크 프로토콜을 mocking 한다.)

  • Service Worker는 웹 애플리케이션의 메인 스레드와 분리된 별도의 백그라운드 스레드에서 실행시킬 수 있는 기술 중 하나이다. Service Worker 덕분에 애플리케이션의 UI Block 없이 연산을 처리할 수 있다.
  • locoahost가 아닌 환경에서는 HTTPS가 기본적으로 제공되는 환경에서만 사용할 수 있다.

브라우저에서의 원리
1. 브라우저가 요청을 한다.
2. Service Worker가 이를 인지한다.
3. Service Worker는 요청을 실제 서버로 보내지 않고 요청을 복사하여 클라이언트 사이드에 있는 MSW 라이브러리로 보낸다.
4. MSW는 해당 요청에 대한 handler를 찾아서 등록된 모의 응답값을 Service Worker를 통해 브라우저에게 전달한다.
5. 이를 통해 실제 서버 존재 여부와 상관없이 실제 요청으로 이어지지 않고 예상할 수 있는 요청에 대해 Mocking이 가능해진다.

개발 흐름
  • 기획자 요구 전달.
  • 프론트엔드 개발자와 백엔드 개발자가 API 스펙 합의.
  • 프론트엔드 개발자는 MSW를 통해 네트워크 레벨에서의 Mocking을 진행한 후 앱 개발.
  • API 없이도 프론트엔드 개발자는 높은 완성도를 갖고 있는 수준에서 기획자와 미리 프론트엔드 애플리케이션 확인하며 피드백 주고받고 그 사이 백엔드 개발자는 API 개발을 진행.
  • 백엔드 개발자가 실제 API를 개발하면, 프론트엔드 개발자는 MSW를 스위치 오프하여 production으로 배포할 수 있는 형태의 개발을 진행.

출처 및 참고 자료

https://github.com/goldbergyoni/javascript-testing-best-practices/blob/master/readme.kr.md

https://techblog.woowahan.com/17721/

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

https://www.youtube.com/watch?v=R7spoJFfQ7U

https://www.youtube.com/watch?v=mIO4Rbe_M74

https://www.youtube.com/watch?v=rkTt1uQ1YHI

https://www.jbee.io/articles/developments/%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%97%90%20%EB%8C%80%ED%95%9C%20%EC%98%A4%ED%95%B4%EC%99%80%20%EC%82%AC%EC%8B%A4

https://tech.kakaopay.com/post/implementing-tdd-in-practical-applications/

https://tech.kakao.com/posts/458

https://blog.lemonbase.team/%EC%9A%B0%EB%A6%AC-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%ED%8C%80%EC%97%90%EB%8A%94-%EC%96%B4%EB%96%A4-%ED%85%8C%EC%8A%A4%ED%8A%B8%EB%A5%BC-%EC%A0%81%EC%9A%A9%ED%95%B4%EC%95%BC%ED%95%A0%EA%B9%8C-a3ea48207cd4

https://tech.madup.com/mock-service-worker/

https://tech.madup.com/front-test-tips/

https://developer-bandi.github.io/post/frontend-testing/

// kent c. dodds 글 번역
https://soojae.tistory.com/74
https://soojae.tistory.com/82?category=1010060
https://soojae.tistory.com/83?category=1010060
https://soojae.tistory.com/84?category=1010060
https://jaehyeon48.github.io/testing/avoid-nesting-when-youre-testing/
https://jymini.tistory.com/73

https://yozm.wishket.com/magazine/detail/2435/
https://yozm.wishket.com/magazine/detail/2483/

https://im-developer.tistory.com/226

https://velog.io/@sehyunny/a-compilation-of-outstanding-testing-articles

https://musma.github.io/2023/07/24/front-end-test-code.html

https://team.modusign.co.kr/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C%EC%97%90%EC%84%9C-%EC%9D%98%EB%AF%B8%EC%9E%88%EB%8A%94-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C-%EC%9E%91%EC%84%B1%ED%95%98%EA%B8%B0-4992409c7f2d

https://ykss.netlify.app/translation/unit-testing-with-jest-react-and-typescript/

https://github.com/ssi02014/react-test-reference-documentation?tab=readme-ov-file

https://techblog.pet-friends.co.kr/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C-%EB%8F%84%EC%9E%85%EA%B8%B0-c3a1865250ee

AHA 법칙 Avoid Hasting Abstraction
https://jaehyeon48.github.io/testing/avoid-nesting-when-youre-testing/
https://kentcdodds.com/blog/aha-testing

MSW 사용 방법

profile
최선을 다한다는 것은 할 수 있는 한 가장 핵심을 향한다는 것

0개의 댓글