7주차에는 바닐라 자바스크립트로 리액트 만들기, 클린 코드에 이어 테스트 코드를 배우게 됐다.
3주차에 리액트에 메모이제이션을 배우며, 리액트의 메모이제이션 훅을 쓰는 것보다 평소에 클린 코드를 통해 최적화할 상황을 만들지 않는 것이 우선이구나라고 생각했다.
클린 코드를 배우며, 클린 코드란 테스트가 용이한 코드로 자연스레 테스트 코드에 대한 호기심이 생겼다.
항해에서 커리큘럼 사이를 자연스레 넘어가도록 의도한 게 아닐까 생각한다.
아무튼 그래서 테스트 코드를 잘 하고 싶다는 생각이 들었다.
'테스트 코드를 잘 한다'라 함은 상황에 맞게 올바른 테스트 도구를 활용하고, 테스트가 용이하도록 코드를 잘 짜는 것을 포괄한다.
테스트란 코드가 의도한 대로 동작하는지 검증하는 것을 의미한다.
바닐라 스크립트로 리액트 만들기 과제에 테스트 코드가 작성되어 있었다.
코드를 바꾸면서 테스트 코드를 실행했고, 그때마다 초록불이 보이면 안심했던 기억이 있다.
그때 코치님께서 테스트 코드의 가장 큰 장점은 내 코드가 안전하다는 걸 보장받는 거라고 하신 말씀이 와닿았다.
테스트 코드는 이런 의미에서 장기적으로 개발 속도를 향상 시킨다고 한다.
코드를 바꿀 때마다 화면에서 일일히 확인할 필요없이 테스트 코드를 통해 빠르게 점검할 수 있기 때문이다.
위에서 얘기한 것처럼 테스트 코드는 클린 코드와 밀접하다.
테스트 코드를 위해서는 클린 코드를 해야하고 클린 코드를 하면 테스트 코드를 작성하기 용이하다.
클린 코드는 단순히 코드를 깔끔하게 짜는 것을 넘어, 동료 개발자에 대한 배려라고 한다.
또한 테스트 코드는 하나의 문서화가 된다.
테스트를 읽으면서 해당 기능을 명확하게 이해할 수 있게 되기 때문이다.
테스트 코드는 인터페이스 위주로 작성해야 한다고 한다.
인터페이스란 세부 구현에 대한 메서드가 아닌 public하게 외부에 노출되는 메서드를 이야기한다.
또한 실제 사용자가 사용하는 것과 최대한 비슷하게 작성하는 것이 좋은 테스트라고 한다.
그러면 브라우저 환경에서 하는 테스트가 더 좋은가?
브라우저는 실제 사용 환경과 유사한 테스트가 가능하지만 구동 속도가 느리고 용량이 크다는 단점이 있다.
반면 Node.js는 실행이 간단하고 속도가 빠르지만 브라우저 동작과 100% 일치하지 않는다.
그러니 각 장점을 활용할 수 있는 적절한 상황에 알맞는 도구를 사용하는 것이 중요하다.
단위 테스트는 가장 작은 단위인 함수나 메서드 등을 독립적으로 검증하는 과정이다.
주로 공통 컴포넌트나 유틸, 헬퍼 함수가 대상이다.
통합 테스트는 단위 테스트된 모듈들을 결합하여 모듈 사이의 상호 작용을 검증한다.
주로 특정 상태를 기준으로 동작하는 컴포넌트 조합, API와 함께 상호 작용하는 컴포넌트 조합이 대상이다.
가능한 한 모킹을 하지 않고 실제와 유사하게 검증하는 것이 좋은데 어쩔 수 없다면 API 응답 같은 것은 msw같은 도구를 활용할 수 있다.
나는 자바스크립트 테스트면 Jest만 있는 줄 알았다.
하지만 Vitest, React Testing Library, Cypress 등등 여러 도구가 있었다.
이번 과제에는 Vitest에서 React Testing Library를 사용하여 단위, 통합 테스트를 했다.
Vitest는 Vite 환경에서 사용할 수 있는, Jest와 비슷한 테스트 러너다.
테스트 러너란, 테스트를 실행하고 결과를 평가하는 도구다.
React Testing Library는 React 컴포넌트 테스트를 위한 라이브러리다.
즉 React 컴포넌트를 브라우저에서 동작하는 것처럼 테스트할 수 있도록 도와준다.
import { render, screen } from "@testing-library/react";
import { describe, it, expect } from "vitest";
import MyComponent from "./MyComponent";
describe("MyComponent", () => {
it("renders a button with text 'Click me'", () => {
render(<MyComponent />);
expect(screen.getByText("Click me")).toBeInTheDocument();
});
});
예를 들어 위 코드에서 Vitest는 describe
, it
, expect
를 제공하여 테스트를 작성할 수 있게 한다.
React Testing Library는 render
, screen
, getByText
를 제공하여 컴포넌트를 렌더링하고 요소를 찾아낸다.
여기서 조금 헷갈렸던 게 expect(기대값).toBeInTheDocument
에서 toBeInTheDocument
는 expect().
뒤에 와서 Vitest에서 제공하는 기능이겠거니 했다.
'그러면 React Testing Library에서 제공하는 건가?'라고 하면 그것도 아니다.
toBeInTheDocument
는 @testing-library/jest-dom
에서 제공한다.
얜 또 뭘까?
@testing-library/jest-dom
은 expect
매처를 확장해서, DOM 요소를 테스트할 수 있도록 도와주는 역할을 한다.
쉽게 얘기하면 DOM 관련 테스트를 더 편하게 도와주는 확장 도구다.
그 외에도 사용자가 발생하는 이벤트를 테스트할 수 있도록 돕는 @testing-library/user-event
도 있다.
각 라이브러리에 대한 사용법과 예시는 나중에 따로 정리할 예정이니 일단은 이정도만 알고 넘어가자.
정리하면 단위 테스트는 Vitest만으로도 가능하다.
하지만 통합 테스트를 할 경우, Vitest
에서 기본적으로 제공되는 테스트 도구들만으로는 불편하다.
이를 돕는 여러 라이브러리가 있는데, 대표적으로 @testing-library/jest-dom
, @testing-library/user-event
가 있다.
단위 테스트가 테스트하는 범위는 명확하다고 생각한다.
유틸 함수들이 제일 대표적인 예시다.
유틸 함수들이 테스트가 용이해지려면 순수 함수로 작성해야 할 것이다.
하지만 통합 테스트가 애매하다.
앞서 얘기했지만 좋은 테스트는 사용자가 사용하는 것과 유사한 거라고 한다.
즉 브라우저 환경에서 동작하는 e2e 테스트가 통합 테스트보다 더 좋은 테스트라고 생각한다.
하지만 규모가 크다면?
규모가 큰 애플리케이션에서 모든 컴포넌트의 상호작용에 대해서 e2e 테스트를 작성하면 배포할 때 테스트하는 시간이 오래 걸리지 않을까?
통합 테스트의 역할은 뭘까?
팀원분들과 얘기를 나누다가, 요구사항이 바뀌는 시기에는 통합 테스트로 작성하다가 확정이 되면 e2e 테스트로 작성하지 않을까란 얘기도 나왔다.
다음주 과제도 테스트 코드인데, 팀원 분들과 테스트 전략을 짜면서 여러 이야기를 나눠봐야 할 것 같다.
설연휴로 일주일을 쉬고 다시 항해를 시작하니, 흐름이 끊긴 느낌이다.
설연휴에도 팀원분들과 스터디를 계획하고 진행했으나, 갑자기 생긴 대상포진으로 내리 쉬었다.
6주차 회고때 밤을 새고 면역력이 떨어진 느낌을 받았다고 적었는데, 정말로 면역력이 떨어진 게 맞았다.
로또 1등될 것 같다고 써놓을 걸 ㅋ
원래 7주차쯤 되면 지치는 건데 설연휴와 건강을 핑계로 삼고 있는 걸지도 모르겠다.
이번주부터는 사이드 프로젝트와 병행했는데, 과제에 신경을 쓰니 사이드 프로젝트에 소홀해지고 사이드 프로젝트에 신경쓰면 과제에 소홀해지는 느낌이다.
시간 분배를 적절하게 하고 적극적으로 지켜야 하는데, 아무래도 강제성이 주입된 일의 느낌이 아니라서 그런지 너무 유연하게 대처한다... ㅎㅎ
그런 의미에서 일과 병행하면서 과제를 완벽하게 끝내는 분들 정말 대단하다.
다음주부터는 오전에 집에서 하고 오후에 카페를 나가서 리프레시를 해볼까?
ㅜ.ㅜ 아프지마세요 원정님
테스트 코드에 대해 작성해 주신글 잘 봤습니다. 제가 찾아보지 않은 내용도 있어서 좋았어요.