프론트엔드 테스트 개념

이수빈·2024년 3월 19일
0

React

목록 보기
17/20
post-thumbnail

테스트의 종류?

  • 테스트를 더 세분화 할 수도 있지만, 일반적으로 3자기 종류로 나눈다.

  • 아래와 같은 버튼 컴포넌트가 존재한다고 해보자

// Button.js

import React from 'react';

const Button = ({ onClick, label }) => (
  <button onClick={onClick}>{label}</button>
);

export default Button;

단위테스트 (Unit Test)

  • 작은 코드 단위들을 테스트. 애플리케이션 소스코드에서 수행됨

  • 함수 클래스 컴포넌트 또는 모듈을 테스트 하는 방식

  • 코드단위가 예상대로 작동하고 요구사항을 만족하는가를 초점을 두는 테스트 방법

  • 버튼이라면..? 세분화해서 쪼갠다면 => 클릭이벤트가 정상적으로 동작하는가? 클릭을 했을 때 올바른 의도한 콜백이 호출되는가 ? 등등을 테스트 가능하다.

  • 이 부분은 요구사항 + 개발자의 의도대로 세분화 가능한 장점이 있음.

  • 툴: Jasmine, Jest, Karma, Mocha

// Button.test.js

import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import Button from './Button';

test('Button renders with correct label', () => {
  const onClickMock = jest.fn();
  const { getByText } = render(<Button onClick={onClickMock} label="Click Me" />);
  const buttonElement = getByText('Click Me');
  expect(buttonElement).toBeInTheDocument();
});

test('Button click fires onClick event', () => {
  const onClickMock = jest.fn();
  const { getByText } = render(<Button onClick={onClickMock} label="Click Me" />);
  const buttonElement = getByText('Click Me');
  fireEvent.click(buttonElement);
  expect(onClickMock).toHaveBeenCalled();
});

통합 테스트 (Integration Test)

  • 통합 테스트는 시스템의 여러 단위 또는 구성 요소 간의 상호 작용을 검증하는 테스트 유형

  • 두개 이상의 모듈이 실제로 연결된 상태를 테스트함 (UI와 API간의 상호작용이 올바르게 일어나는지, 또는 STATE에 따른 UI의 변경이 올바르게 동작하는지 등등..)

  • 서로 다른 단위가 함께 동작하면서 흐름에 맞게 잘 동작하고, 예상한 결과를 생성하는지를 테스트한다.

예: 카카오 프렌즈샵에서 상품을 구매하는 경우, 통합 테스트는 구매시 고객의 잔액, 재고 업데이트, 영수증 생성시 다른 구성 요소 간의 상호 작용이 잘 되어 구매가 완료되는지 확인한다.

  • 툴 종류: Jest, Testing Library

  • 컴포넌트 테스트라고도 생각 할 수 있다. 버튼이라면, 통합테스트에서는 Form 컴포넌트 안에서 쓰이는데 이벤트 callback이 올바르게 동작하는가? 를 테스트 할 수 있다.

import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import Button from './Button';
import Form from './Form';

test('Form submits when button is clicked', () => {
  const { getByLabelText, getByText } = render(<Form />);
  const inputElement = getByLabelText('Username');
  fireEvent.change(inputElement, { target: { value: 'testuser' } });

  const buttonElement = getByText('Submit');
  fireEvent.click(buttonElement);

  // assert form submission
});

E2E테스트 (End to End test)

  • 실제로 배포되었을 때의 문제점을 확인하기 위한 테스트

  • 시작부터 끝까지 전체 흐름을 확인하는 테스트 유형임, 코드단위가 아니라 브라우저 자체를 로드해 테스트 하기 때문에 비용이 많이든다.

  • 툴 종류: Cypress, Puppeteer

  • 예: 카카오 프렌즈샵에서 상품을 구매하는 경우 : 고객이 카카오 로그인 => 상품을 선택하여 장바구니에 추가 => 상품 구매
    => 결제 방식 선택 => 구매 완료 => 구매 영수증을 고객 메일로 전송하는 일련의 과정을 테스트

const puppeteer = require('puppeteer');

describe('Shopping', () => {
  let browser;
  let page;

  beforeAll(async () => {
    // 테스트 환경 설정
    browser = await puppeteer.launch();
    page = await browser.newPage();
    await page.goto('http://localhost:3000');
    await page.type('[data-testid="login-email"]', 'user@example.com');
    await page.type('[data-testid="login-password"]', 'password');
    await page.click('[data-testid="login-button"]');
    await page.waitForNavigation();
  });

  afterAll(async () => {
    // 브라우저 종료
    await browser.close();
  });
describe('End-to-End Tests', () => {
  it('Visits the homepage', () => {
    cy.visit('/');
    cy.contains('Welcome to My App');
  });

  it('Clicks the button and checks the result', () => {
    cy.visit('/');
    cy.contains('Click Me').click();
    cy.contains('Button clicked!');
  });
});

그렇다면 어떤 테스트를 선택해야해?

  • 단위테스트의 장점 => 세분화해서 테스트가능 + 테스트 실행시간이 E2E보다 빠르다 + 어디서 문제가 발생했는지 쉽게 알 수 있다.

  • 단점 : 모든 세부사항을 개발자가 컨트롤하기에는 작성해야 할 코드량이 너무 많다.

  • E2E테스트의 장점 => 사용자가 사용하는 방식으로 테스트가능함 (즉 Flow에 문제가 없다면, 사용자가 프로덕트를 사용하는데에도 문제가 없다는 뜻이 됨)

  • 단 직접 브라우저 환경에서 테스트 하기 때문에 시간이 올래걸림 + 에러가 발생했다면 어디서 발생했는지 찾기가 Unit test에 비해 어려움.

  • 결국 잘 조합해서 사용하는게 중요하다.

TDD란?

  • Test Driven Development의 약자 => 테스트 주도 개발, 작은 단위의 테스트를 먼저 작성하고 이를 통과하는 코드를 추가하는 단계를 반복하여 구현함.

Red 단계에서는 실패하는 테스트 코드를 먼저 작성한다.
Green 단계에서는 테스트 코드를 성공시키기 위한 실제 코드를 작성한다.
Blue 단계에서는 중복 코드 제거, 일반화 등의 리팩토링을 수행한다.

  • 중요한 것은 실패하는 테스트 코드를 작성할 때 까지 실제 코드를 작성하지 않는 것과, 실패하는 테스트를 통과할 정도의 최소 실제 코드를 작성해야 하는 것이다.

  • 일반적인 개발 순서 : '요구사항 분석 -> 설계 -> 개발 -> 테스트 -> 배포' => 만약 요구사항 (기획이 바뀐다면) => 처음부터 다시 설계하고 개발해야하는 단점이 존재함

  • 이러한 과정에서 자체적으로 TEST 하는 비용 증가 가능

  • 디자인(설계) 단계에서 프로그래밍 목적을 반드시 미리 정의해야만 하고,

  • 또 무엇을 테스트해야 할지 미리 정의(테스트 케이스 작성)해야만 한다. 

  • 개인적으로 전체적인 큰 틀을 알고있어야 적용하기 수월하다고 생각 + 기획단에서 많은것이 자주 바뀌는 경우에 적용하기 좋아보임

그렇다면 무엇을 테스트해야할까?

  • 가장 큰 고민이, 어디까지 테스트를 작성해야 하고 무엇을 테스트해야 하는가를 선정하는게 어렵다.

  • 만약 모든 UI과 기능, FUNCTION TEST를 작성하게 된다면 그 만큼 TEST 코드를 작성하는데에도 비용이 많이 들 것이기 때문

  • 이런 것들이 고민될때는 아래와 같은 원칙을 준수하자

Fast: 유닛테스트는 빠르게 실행되어야 한다. 즉, Mocking을 이용해 네트워크 등에 대한 의존성을 낮춘다고 생각할 수 있다.
Isolated: 최소한의 단위로 독립적으로 만든다. 하나에 하나만!
Repeatable: 테스트를 반복해도 같은 결과를 리턴한다. 이것도 외부 환경에 의존해서 매번 바뀌는 상황을 유의하라는 것이다.
Self-Validating: 항상 테스트의 성공, 실패 결과가 자동으로 나와야 한다. 이는 jest와 같은 프레임워크를 사용하여 실행하고 결과 값을 검증함으로서 지킬 수 있다.
Timely: 적절한 때에 작성되어야 한다. 즉, 배포하기 전에 미리 테스트코드를 작성한다!

REF) CLEAN CODE FIRST 원칙

[1] 특정한 포맷을 준수하는가?
-> 특수문자, 이메일, 전화번호 등의 형식을 테스트한다.
[2] 데이터의 순서를 준수하는가?
-> 가격순, 인기도순과 같은 순서가 있는 데이터일 경우, 이를 준수하는지를 테스트해 볼 수 있다.
[3] 숫자의 범위가 있는가?
-> 너무 작거나 큰 숫자, 정수, 음수, 실수 등의 숫자 범위를 준수하는지 테스트한다.
[4] 특정한 상황에 따른 ~한 동작을 하는가?
-> 다른 상황이 주어졌을 때, 예상되는 동작을 하는지 테스트한다.
[5] 값이 존재하지 않을 때, 에러처리가 되는가?
[6] 값이 하나도 없을 때, 하나만 있을 때, 여려개가 있을 때 처리 방식은?
[7] 시간을 준수하는가?
-> 정해진 시간이내의 작업인지, 지역시간이 제대로 맞춰져 있는지를 테스트한다.

  • 내가 설계자라면 ? => E2E 테스트 작성기반으로 자주변하는 로직이나 코어로직들은 UNIT TEST를 작성할 것 같다.

ref) Jest+React를 이용한 단위테스트 : https://ykss.netlify.app/translation/unit-testing-with-jest-react-and-typescript/

프론트엔드 단위테스트 모범사례 : https://velog.io/@surim014/frontend-unit-testing-best-practices#6-%EB%8B%A4%EC%96%91%ED%95%98%EA%B2%8C-%EC%9E%85%EB%A0%A5%EB%90%98%EB%8A%94-%EB%A7%A4%EA%B0%9C%EB%B3%80%EC%88%98-%ED%85%8C%EC%8A%A4%ED%8A%B8%ED%95%98%EA%B8%B0

https://soojae.tistory.com/74#TDD%EC%9D%98%20%EC%9D%B4%EC%A0%90-1

우테코 테크톡 : https://www.youtube.com/watch?v=MN7Pw4mK6lU

TDD : https://inpa.tistory.com/entry/QA-%F0%9F%93%9A-TDD-%EB%B0%A9%EB%B2%95%EB%A1%A0-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A3%BC%EB%8F%84-%EA%B0%9C%EB%B0%9C#%EC%9D%BC%EB%B0%98_%EA%B0%9C%EB%B0%9C_%EB%B0%A9%EC%8B%9D_vs_tdd_%EA%B0%9C%EB%B0%9C_%EB%B0%A9%EC%8B%9D

profile
응애 나 애기 개발자

0개의 댓글