Vitest! test 라이브러리 도입하기!

김인태·2024년 11월 8일
0
post-thumbnail

🏃‍♂️개요

요즘(몇 년 전 부터 꾸준히 이야기가 많았음) TDD(Test Driven Development) 에 대한 이야기가 많습니다.

하지만 스타트업이나 빨리 개발해서 아웃풋을 뽑아내야하는 그런 상황이라면 사실 테스트를하면서

개발하는 것은, 어느 정도 무리가 있지 않을까? 생각합니다.

그럼에도 불구하고 왜 test를 해야할까요? 저도 의문이 생겼습니다.

테스트에 대한 인강을 듣고있긴 하지만, 지금 내 프로젝트들은 잘 구동되고 최적화도 열심히 하고 있는데

굳이 테스트를 하면서까지 로직을 만들어야하는가? 라는 생각도 듭니다.

그러면 테스트는 무엇이고, 왜 써야하고, 어떻게 써야하는지 알아봅시다!

👀 테스트의 종류

테스트는 여러가지 종류가 있습니다.

단위 테스트(Unit Test)

가장 작은 단위(함수, 메소드, 클래스)를 독립적으로 테스트

통합 테스트 (Integration Test)

여러 모듈이나 서비스가 함께 잘 작동하는지 테스트

E2E 테스트 (End-to-End Test)

실제 사용자 시나리오 전체를 테스트

UI/컴포넌트 테스트

UI 컴포넌트의 동작과 렌더링을 테스트

등등.. 그 이외에도 회귀 테스트, 스냅샷 테스트 등의 여러가지 테스트 들이 있습니다.

이렇게 복잡하고 종류도 많은 테스트들 왜 해야할까요?

🧐 테스트는 왜 할까?

1. 버그 예방과 빠른 발견

// 실제 자주 발생하는 케이스
function calculateDiscount(price, quantity) {
  // 수정 전: 할인율 계산 오류
  return price * quantity * 0.1;
  
  // 수정 후: 올바른 할인 계산
  return price * quantity * (1 - 0.1);
}

// 테스트가 있다면 즉시 발견 가능
test('할인 계산', () => {
  expect(calculateDiscount(1000, 2)).toBe(1800);
});

내 예상과 다르게 결과가 나온 경우들이 있지않나요? 저는 엄청 많습니다..

이러한 함수들의 결과가 내가 원하는 경우처럼 나오는지 확인하면 좋겠죠?

생길 수 있는 버그를 예방하고 발견하는데 있어서 장점이 있습니다.

2. 리팩토링 시 안정성 확보

// Before: 레거시 코드
function handleSubmit(data) {
  // 복잡한 로직...
}

// After: 리팩토링
function validateData(data) {
  // 데이터 검증 로직
}

function processData(data) {
  // 데이터 처리 로직
}

// 테스트가 있다면 리팩토링 후에도 
// 같은 결과가 나오는지 즉시 확인 가능

함수를 작성하고 리팩토링한 경험들이 있으시나요? 성능적인 측면이나 가독성 등에서 개선하기 위한 노력들은

꼭 필요하다고 생각합니다. 근데 리팩토링 하는 과정속에서 이전과 다른 결과가 나온다면

그 리팩토링은 안하느니만 못하겠죠?

하지만 테스트를 작성한다면 리팩토링을해도 안전하게 할 수 있다~

3. 문서화!

describe('장바구니 기능', () => {
  it('상품 추가 시 총액이 올바르게 계산된다', () => {
    const cart = new Cart();
    cart.addItem({ price: 1000, quantity: 2 });
    expect(cart.total).toBe(2000);
  });

  it('할인 쿠폰 적용 시 할인이 반영된다', () => {
    // ... 
  });
});
// 이 테스트 코드만 봐도 기능의 동작 방식을 이해할 수 있음

굳이 코드에 주석을 달지 않아도 설명을 함수에 적기 때문에 바로 어떤 기능인지 알 수 있겠죠?

그러면 인수인계하거나 서로 공유할 때도 편하게 할 수 있을겁니다~

🤩 어떻게 쓸 수 있을까요?

아주 다양~ 하게 적용할 수 있습니다! 저 위에 테스트의 종류들을 보셨다시피

함수의 아주 작은 조각부터 브라우저에 나타나는 전체적인 시나리오까지 전부 테스트 할 수 있습니다!

하지만 현실적으로는 점진적으로 도입하는 것이 좋지 않을까? 라고 생각합니다.

이유

  1. test 라이브러리 (jest, vitest 등 이번 프로젝트에서는 vitest 쓸꺼임 ) 의 이해도가 떨어지기 때문에 학습을 병행하면서 테스트를 도입해야한다.
  2. 기존의 태스크를 진행하면서 본래 기능에 테스트 코드를 짜야한다.

이러한 이유들로 인해서 점진적으로 테스트를 도입하려고 합니다.

그래서 저는 세 가지의 부분에서 테스트를 진행해보고자 합니다.

  1. 핵심 비즈니스로직
  2. 자주 버그가 발생하는 부분
  3. 변경이 잦은 코드

이 세 부분에서 테스트를 진행하고 제품의 안정성을 높여보도록 하죠~~!

왜 Vitest?

[vitest 공식문서] https://vitest.dev/guide/why.html

저는 현재 프로젝트를 vite + react + typescript 를 사용하고 있어서

편한 호환성으로 이득을 취하고자 vitest를 사용하려고 합니다. 자세한 내용은 위에 나와있습니다.

음.. 요약하자면

  1. vite 기반이라 빠르고
  2. 설정하기가 쉽고
  3. react, vue 등의 모던 프레임워크와 호환성이 좋고
  4. jest와 api 가 유사하고 ← 지금 인강듣는 부분이 jest라 아주 좋네요 ㅎㅎ
  5. 파일 변경시에 즉시 테스트할 수 있어 빠른 피드백이 가능하다!

라네요~

이제 설치 한 번 해볼까요?

💥 Vitest 세팅

설치


# Vitest 및 관련 패키지 설치

npm install -D vitest
npm install -D @testing-library/react @testing-library/jest-dom
npm install -D jsdom
npm install -D @testing-library/user-event @testing-library/react-hooks

저는 리액트 훅도 테스트할꺼니깐 관련 라이브러리들 설치해줍니다~

세팅

vite.config.ts

/// <reference types="vitest" />
/// <reference types="vite/client" />

export default defineConfig({
   base: "/",
   test: {
    globals: true,
    environment: "jsdom",
    css: true,
    coverage: {
      reporter: ["text", "json", "html"],
    },
  },
})

tsconfig.app.json

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "composite": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@components": ["src/components/*"]
    },
    // types 추가 해주면 됩니다! 요기!
    "types": ["vitest/globals", "@testing-library/jest-dom"],
    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "verbatimModuleSyntax": true
  },
  "include": ["src"]
}

테스트를 테스트 해보기

잘 설치가 됐는지 테스트 한 번 해볼까요

일단 test 파일은 test 파일을 따로 만들던가 혹은 그 test 하고 싶은 파일과 같이

[파일명].spec.ts 를 같이 놓는 방법으로 위치시키는데

저는 같이 있는게 조금 더 관리하기 편할 것 같아서 같은 위치에 두고 한 번 테스트 해보겠습니다.

아무곳에서나 test.ts를 만들어줍니다

export function addTest(a: number, b: number) {
  return a + b;
}

같은 위치에 test.spec.ts를 만들어줍니다.

import { addTest } from "./test";

describe("vitest 잘되는지 체크", () => {
  it("더하기 테스트", () => {
    expect(addTest(2, 3)).toBe(5);
  });
});

잘되는지 체크해보겠습니다!

겁나 잘 돌아가죠?

저는 참고로 vitest vscode extension을 설치해서 cli 방식말고

클릭하는 방법으로 test 코드를 실행시켰습니다.

자 오늘은 이렇게 해서 테스트 코드는 무엇이고, 왜 써야하는지, 어떻게 써야하는지 , 그리고 vitest 세팅까지 한 번 알아봤습니다! 다음에는 react-hook 이나 비동기 함수등의 테스트를 어떻게 하는지 한 번 알아보도록 하겠습니다!

겁나 잘 돌아가죠?

저는 참고로 vitest vscode extension을 설치해서 cli 방식말고

클릭하는 방법으로 test 코드를 실행시켰습니다.

자 오늘은 이렇게 해서 테스트 코드는 무엇이고, 왜 써야하는지, 어떻게 써야하는지 , 그리고 vitest 세팅까지 한 번 알아봤습니다! 다음에는 react-hook 이나 비동기 함수등의 테스트를 어떻게 하는지 한 번 알아보도록 하겠습니다!

profile
새로운 걸 배우는 것을 좋아하는 프론트엔드 개발자입니다!

0개의 댓글