Front-end/Test

[Test] 프론트엔드 테스팅 1편: Jest로 시작하는 단위 테스트 🧪

xeunnie 2025. 2. 2. 01:00
728x90
반응형

프론트엔드 테스팅 Jest 톺아보기! 🧪 

 프론트엔드 개발에서 테스팅은 우리가 만든 코드가 의도한 대로 동작하는지 검증하는 중요한 과정이에요.
코드의 품질을 높이고, 버그를 사전에 예방하며, 유지보수를 용이하게 만드는 데 필수적입니다. 
하지만 많은 개발자가 테스트를 귀찮아하고, 필요성을 잘 느끼지 못하는 경우가 많죠. 🤔 (제가 그랬네요,,,)
 
의외로 막상 시작해보면 꽤 재밌는 부분들이 많습니다!
자, 이제 Jest부터 시작해봅시다! 🚀


🎯  왜 테스트가 필요할까?

프론트엔드에서 테스트를 하지 않아도 당장 동작하는 UI를 만들 수 있어요. 하지만 다음과 같은 문제들이 발생할 수 있죠.

  • 😱 예기치 않은 버그 발생: 작은 변경이 전체 기능을 망가뜨릴 수도 있음
  • 🛠 리팩토링이 어려움: 코드 수정할 때마다 정상 동작하는지 확인해야 함
  • 🤯 수동 테스트의 한계: 모든 기능을 직접 클릭해서 테스트하는 건 비효율적

💡 테스트 자동화를 하면?

  • ✅ 코드 변경에도 안정적인 동작 보장
  • ✅ 빠르게 피드백을 받아 버그 방지
  • ✅ 반복적인 수동 테스트를 줄여 개발 생산성 증가

테스트의 진정한 필요성은 기능이 추가됐을 때 라고 합니다. 어디서 오류가 나는지 어디에 허점이 있는지 아주 상세하게 알 수 있어요.


🧪 Jest란?

Jest는 Facebook에서 만든 JavaScript 테스트 프레임워크로, 프론트엔드 단위 테스트를 쉽게 작성할 수 있도록 도와줘요.
 

✅ Jest의 특징

  • ✔️ 빠른 실행 속도 – 테스트를 병렬로 실행해 속도가 빠름
  • ✔️ 간단한 설정 – 별도 설정 없이 바로 사용 가능
  • ✔️ Mocking 지원 – API 호출이나 함수 호출을 가짜(mock)로 대체 가능
  • ✔️ 스냅샷 테스트 지원 – UI 변경을 감지하는 기능

⚡ Jest 설치 및 기본 설정

📌 Jest 설치하기

먼저, Jest를 설치해볼게요.

yarn add --dev jest

📌 TypeScript를 사용한다면?

yarn add --dev @types/jest ts-jest

 

📌 React 프로젝트에서 추가적으로 필요한 패키지

npm install --save-dev babel-jest @babel/preset-env @babel/preset-react

 
설치가 완료되면 package.json에 아래와 같이 Jest 설정을 추가해주세요.

"scripts": {
  "test": "jest"
}

 
이제 npm test 또는 yarn test 명령어를 실행하면 Jest가 실행됩니다. 🎉
(위는 간소화된 버전으로 다양한 기능들을 사용하고 싶다면 더 많은 패키지들이 피룡합니다!)


🎯 Jest의 동작 원리

Jest는 테스트 러너(Test Runner) 역할을 합니다. 즉, 작성된 테스트 코드를 실행하고, 테스트 결과를 자동으로 비교하여 성공/실패를 판별하는 도구예요.
 

✅ Jest가 테스트를 실행하는 과정

  • 1️⃣ npm test 실행 → Jest가 프로젝트에서 *.test.js 또는 *.spec.js 파일을 찾음
  • 2️⃣ 각 테스트 파일을 독립적인 환경에서 실행
  • 3️⃣ expect()로 작성된 검증(Assertion) 코드를 실행
  • 4️⃣ 예상값과 실제값을 비교
  • 5️⃣ 테스트 결과를 터미널에 출력

💡 Jest는 테스트를 실행할 때

각 테스트 파일을 독립적인 환경에서 실행하기 때문에, 하나의 테스트가 다른 테스트에 영향을 미치지 않아요.


🤓 Jest 작성 규칙

1️⃣ describe

  • ✔️ 용도: 관련된 테스트를 그룹화합니다.
  • ✔️ 형식: describe('설명', () => { ... });

📌 코드 예시

describe('수학 함수 테스트', () => {
    // 관련 테스트를 여기서 작성
});

2️⃣ test 또는 it

  • ✔️ 용도: 개별 테스트 케이스를 정의합니다.
  • ✔️ 형식: test('설명', () => { ... }); 또는 it('설명', () => { ... });
test('1 + 2는 3이어야 한다', () => {
    expect(sum(1, 2)).toBe(3);
});

3️⃣ expect

  • ✔️ 용도: 예상 결과를 정의합니다. 테스트가 성공하기 위해서는 이 예상 결과가 충족되어야 합니다.
  • ✔️ 형식: expect(값).toBe(기대값);
expect(sum(1, 2)).toBe(3);

🔍 Jest의 비교 메서드 (Matcher)

Jest는 다양한 비교 메서드(Assertion Matcher)를 제공해요.

✅ 기본적인 비교 메서드

expect(value).toBe(expected); // === 비교
expect(value).not.toBe(expected); // !== 비교
expect(value).toEqual(expected); // 객체/배열 비교
expect(value).toBeTruthy(); // true 값인지 확인
expect(value).toBeFalsy(); // false 값인지 확인

✅ 배열과 객체 비교

toBe()는 객체의 참조(메모리 주소)를 비교하지만, toEqual()은 객체의 속성 값을 비교해요.

test('객체 비교 테스트', () => {
  expect({ name: 'Alice' }).toEqual({ name: 'Alice' }); // ✅ 통과
  expect({ name: 'Alice' }).toBe({ name: 'Alice' }); // ❌ 실패
});

🏗  Jest로 단위 테스트 작성하기

1️⃣ 첫 번째 테스트: 숫자 연산 검증

테스트 파일을 생성해볼까요? sum.js 파일을 만들고, 아래처럼 간단한 함수를 작성해요.

// sum.js
export function sum(a, b) {
  return a + b;
}

 
이제 sum.test.js에서 Jest 테스트를 작성해봅시다.

// sum.test.js
import { sum } from './sum';

test('1 + 2는 3이어야 한다', () => {
  expect(sum(1, 2)).toBe(3);
});

 

✅ 코드 설명

  • ✔️ test(description, callback) – 테스트 케이스 정의
  • ✔️ expect(value).toBe(expected) – 값이 예상대로 나오는지 검증

이제 터미널에서 실행해보세요!

npm test

테스트 통과! 🎉

터미널 출력 예시:

 PASS  ./sum.test.js
  ✓ 1 + 2는 3이어야 한다 (5ms)

🏗  Jest 테스트 오류 확인 및 디버깅

테스트를 실행하면 Jest는 다음과 같은 정보를 터미널에 출력합니다.

성공한 테스트 예시

 PASS  ./sum.test.js
  ✓ 1 + 2는 3이어야 한다 (5ms)
  • ✔️ PASS는 테스트가 정상적으로 통과했다는 의미
  • ✔️ ✓ 표시가 나오면 테스트가 성공

 

🚨 4. 테스트 오류 확인 및 디버깅

테스트 코드가 실패하면, Jest는 실제 결과와 기대한 결과의 차이를 알려줍니다.
 
📌 예를 들어, 아래와 같이 sum(1, 2)가 잘못된 결과(4)를 반환한다고 가정해볼게요.

test('1 + 2는 3이어야 한다', () => {
  expect(sum(1, 2)).toBe(4); // ❌ 오류 발생
});

 
📌 터미널에서 출력되는 에러 메시지

 FAIL  ./sum.test.js
  ✕ 1 + 2는 3이어야 한다 (10ms)

  ● 1 + 2는 3이어야 한다

    expect(received).toBe(expected) // Object.is equality

    Expected: 4
    Received: 3

      2 | test('1 + 2는 3이어야 한다', () => {
      3 |   expect(sum(1, 2)).toBe(4);
        |                      ^

 
 

  • ✔️ FAIL이 나오면 테스트 실패
  • ✔️ Expected: 3, Received: 4 → 기대한 값과 실제 값이 다름

✅ 오류 해결 방법

  • Expected: 4, Received: 3 👉 예상한 값(4)과 실제 값(3)이 다름
  • 오류가 발생한 코드의 줄 번호(2 | test('1 + 2는 3이어야 한다') 표시됨
  • sum(1, 2)를 다시 확인해 3이 나오도록 수정

🏗  Jest로 비동기 코드 테스트하기

프론트엔드에서는 API 요청을 다루는 경우가 많아요. Jest는 비동기 코드도 테스트할 수 있습니다.

// fetchUser.js
export async function fetchUser(id) {
  const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
  return response.json();
}

 
이제 fetchUser.test.js에서 Jest 테스트를 작성해봅시다.

// fetchUser.test.js
import { fetchUser } from './fetchUser';

test('API에서 사용자 정보를 가져와야 한다', async () => {
  const user = await fetchUser(1);
  expect(user).toHaveProperty('id', 1);
});

 
💡 비동기 테스트에서는 async/await을 사용해서 데이터를 기다린 후 검증하면 돼요.


🏗  Jest Mocking: API 호출 없이 테스트하기

실제 API를 호출하지 않고 가짜(mock) 데이터를 사용해서 테스트할 수도 있어요.

// fetchUser.js
export async function fetchUser(id) {
  const response = await fetch(`https://api.example.com/users/${id}`);
  return response.json();
}

 
테스트 코드에서 jest.fn()을 사용해 API 호출을 모킹(mocking)할 수 있어요.

// fetchUser.test.js
import { fetchUser } from './fetchUser';

jest.mock('./fetchUser', () => ({
  fetchUser: jest.fn(),
}));

test('Mocked API 호출 테스트', async () => {
  fetchUser.mockResolvedValue({ id: 1, name: 'John Doe' });

  const user = await fetchUser(1);
  expect(user).toEqual({ id: 1, name: 'John Doe' });
});

💡 실제 API 요청을 하지 않으므로 테스트 속도가 빨라지고 안정성이 높아집니다. 🚀


📸 Jest 스냅샷 테스트

스냅샷 테스트는 UI가 예상대로 렌더링되는지 확인하는 테스트 방법이에요.
Jest는 컴포넌트의 출력을 파일로 저장한 후, 이후 실행 시 기존 스냅샷과 비교하여 변경 여부를 확인해요.

✅ 스냅샷 테스트 예제

import renderer from 'react-test-renderer';
import Button from './Button';

test('버튼 스냅샷 테스트', () => {
  const tree = renderer.create(<Button label="Click me" />).toJSON();
  expect(tree).toMatchSnapshot();
});

 
📌 첫 실행 시, Jest는 __snapshots__ 폴더에 스냅샷 파일을 생성해요.
📌 이후 변경된 UI가 기존 스냅샷과 다르면 테스트가 실패하고, 수정 여부를 묻습니다.

UI 변경 후 스냅샷 업데이트

npm test -- -u

🎯 마무리

✅ Jest는 단위 테스트를 쉽게 작성할 수 있도록 도와주는 강력한 도구
다양한 비교 메서드(Assertion Matcher) 제공
비동기 코드, API 호출, Mocking 등 다양한 방식으로 테스트 가능
터미널에서 테스트 결과 확인 및 오류 디버깅 가능
스냅샷 테스트로 UI 변경 감지 가능
 
🌷 전설의 개발자가 되어봅시당! 🌷

728x90
반응형