테스팅 코드 작성해 보기

no-pla·2024년 3월 18일
0

React Testing Library

목록 보기
3/4
post-thumbnail

Testing Library를 이용해 테스팅 코드를 작성해 보자.

이번에 새로 진행하는 프로젝트를 TDD 방식으로 진행하기로 결정했다. 그래서 가장 먼저 회원가입 페이지의 테스팅 코드를 작성해 보기로 했다.

import { fireEvent, render, screen } from "@testing-library/react";

import RegisterForm from "../../app/register/components/RegisterForm";

  

describe("회원가입 페이지", () => {
	const placeholderCases = [
		["email", /email/i],
		["password", /password/i],
		["confirm Password", /confirm password/i],
		["nickname", /nickname/i],
	];

describe("마크업 테스트", () => {
	it("회원가입 필드가 모두 제대로 랜더링되었는지 확인한다.", () => {
		render(<RegisterForm />);
		const inputs = screen.getAllByRole("textbox");
		expect(inputs).toHaveLength(4);
	});

  

it.each(placeholderCases)(
	"회원가입 필드의 %p input이 옳은 placeholder를 가지고 있는지 확인한다.",
		(_, placeholder) => {
			const placeholderInput = screen.getByPlaceholderText(placeholder);
			expect(placeholderInput).toBeInTheDocument();
		}
);

  

it("로그인 페이지로 이동하는 링크와 플로우가 작성되었는지 확인한다.", () => {
	render(<RegisterForm />);
	const loginLink = screen.getByRole("link", {
	name: /login/i,
});

	expect(loginLink).toBeInTheDocument();
	fireEvent.click(loginLink);
	expect(window.location.href).toContain("/login");
});

it("회원가입 버튼은 기본적으로 비활성화 상태여야 한다.", () => {
	render(<RegisterForm />);
	const registerButton = screen.getByRole("button", {
	name: /register/i,
});
	expect(registerButton).toBeDisabled();
});

});

  

describe("유효성 검사 테스트", () => {

it("이메일 란이 비어 있으면, 버튼이 비활성화되어야 한다.", () => {

render(<RegisterForm />);

  

const emailInputs = screen.getByRole("textbox", {

name: /email/i,

});

const registerButton = screen.getByRole("button", {

name: /register/i,

});

  

// 이메일이 비어 있으면 비활성화 된다.

fireEvent.change(emailInputs, { target: { value: "" } });

expect(registerButton).toBeDisabled();

});

it("비밀번호 란이 비어 있으면, 버튼이 비활성화되어야 한다.", () => {

const emailInputs = screen.getAllByRole("textbox", {

name: /email/i,

});

const registerButton = screen.getAllByRole("button", {

name: /register/i,

});

expect(emailInputs).toBe("");

expect(registerButton).toBeDisabled();

});

  

it("이메일 정규식을 통과하지 못하면, 버튼이 비활성화되고 경고 문구가 떠야 한다.", () => {

const emailInput = screen.getByLabelText(/email/i);

const registerButton = screen.getByRole("button", { name: /register/i });

const errorMessage = screen.getByRole("paragraph", {

name: /error/i,

});

const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

  

// 기본적으로 에러 메시지가 뜨지 않는다.

expect(errorMessage).not.toBeInTheDocument();

  

// 잘못된 형식의 이메일을 입력하면 메시지가 뜬다.

fireEvent.change(emailInput, { target: { value: "userExampleCom" } });

expect("emailInput").not.toMatch(emailRegex);

expect(errorMessage).toBeInTheDocument();

expect(registerButton).toBeDisabled();

  

// 옳은 형식의 이메일을 입력하면 메시지가 사라진다.

fireEvent.change(emailInput, { target: { value: "user@example.com" } });

expect("user@example.com").not.toMatch(emailRegex);

expect(errorMessage).not.toBeInTheDocument();

});

it("비밀번호가 8자 이하면, 버튼이 비활성화되고 경고 문구가 떠야 한다.", () => {

const passwordInput = screen.getByRole("textbox", {

name: /password]/i,

});

const registerButton = screen.getByRole("button", { name: /register/i });

const passwordRegex =

/^(?=.*[a-zA-Z0-9!@#$%^&*()-_+=])[a-zA-Z0-9!@#$%^&*()-_+=]{8,}$/;

const errorMessage = screen.getByRole("paragraph", {

name: /error/i,

});

  

// 기본적으로 버튼이 비활성화 된다.

expect(registerButton).toBeDisabled();

// 경고 문구가 보이지 않아야 한다.

expect(errorMessage).not.toBeInTheDocument();

  

// 8자 이하의 비밀번호를 입력한 상태면 비활성화 된다.

fireEvent.change(passwordInput, { target: { value: "wrongPw" } });

expect("wrongPw").not.toMatch(passwordRegex);

expect(errorMessage).toBeInTheDocument();

  

// 8자 이상의 비밀번호를 입력하면 정규식을 통과한다. 에러 문구가 보이지 않아야 한다.

fireEvent.change(passwordInput, { target: { value: "correctPassword" } });

expect("correctPassword").toMatch(passwordRegex);

expect(errorMessage).not.toBeInTheDocument();

});

});

});

처음 작성해 보는 테스팅 코드인 만큼, 간단한 테스트 코드를 작성해 보는 연습을 했다.

먼저 describe로 회원 가입 페이지로 1차 분류를, 2차로 테스팅 하는 로직을 분류를 해두었다.
가장 먼저 작성한 코드는 특정 컴포넌트가 존재하는지 확인하는 코드다.

	it("회원가입 필드가 모두 제대로 랜더링되었는지 확인한다.", () => {
		render(<RegisterForm />);
		const inputs = screen.getAllByRole("textbox");
		expect(inputs).toHaveLength(4);
	});

테스트 코드 작성법은 RTL는 구조가 동일하다.

it('테스트할 로직 설명', ()=>{
	render(<Component />) // 테스트할 컴포넌트 랜더링
	const elements = screen.get<가져오는 방식 정의>('가져올 컴포넌트의 특징 작성')
	expect(테스트 할 컴포넌트).to<테스트 할 방식 정의>(테스트 요소 작성)
})
  1. it(혹은 test)에 무슨 테스트를 진행하는지 설명을 작성하고, 해당 테스트를 하는 함수를 작성한다.
  2. 내부에서는 render 메서드를 이용하여 테스트를 할 컴포넌트를 랜더링하고, screen 메서드로 해당 컴포넌트에 접근한다.
  3. 랜더링한 해당 컴포넌트 내에서 특정 요소에 접근하기 위하여, getByRole, getByLabelText 등의 방식을 사용하여 가져온다.
  4. 마지막으로 expect 메서드로 가장 중요한, 테스트를 하는 코드를 작성한다.

render()로 RegisterForm을 랜더링한 뒤, getAllByRole 메서드로 모든 input들을 가져왔다. 그리고 input이 4개(이메일, 비밀번호, 비밀번호 확인, 닉네임)을 가지고 있는지 확인하는 코드를 작성했다.

fireEvent

특정 이벤트가 발생시키기 위해서 fireEvent 메서드를 사용할 수 있다.

fireEvent.change(emailInput, { target: { value: "userExampleCom" } });
fireEvent.click(registerButton);

jest에서 특정 input에 입력을 하기 위해서,
fireEvent.change(emailInput, { target: { value: "userExampleCom" } });
처럼 작성한다.

fireEvent의 작성 구조는 다음과 같다.

fireEvent.<이벤트 방식>(이벤트를 발생시킬 요소, 옵션) // 옵션은 선택 사항이다.

fireEvent 메서드를 통해, 다양한 이벤트를 발생시켜 테스트 코드를 작성할 수 있다.

it.each / test.each

변수만 다르고 같은 테스트를 반복한다면, each를 통해 반복된 작성을 없앨 수 있다.

	const placeholderCases = [
		["email", /email/i],
		["password", /password/i],
		["confirm Password", /confirm password/i],
		["nickname", /nickname/i],
	];

it.each(placeholderCases)(
	"회원가입 필드의 %p input이 옳은 placeholder를 가지고 있는지 확인한다.",
		(_, placeholder) => {
			const placeholderInput = screen.getByPlaceholderText(placeholder);
			expect(placeholderInput).toBeInTheDocument();
		}
);

각 input이 올바른 placeholder를 가지고 있는지 확인하는 테스팅 로직이다. 일반적으로 테스팅 로직을 작성한다면, 이메일, 비밀번호, 비밀번호 확인, 닉네임 필드를 각각 테스팅하는 로직을 작성해야 하지만, it.test를 사용하면 한 번에 테스트를 진행할 수 있다.

it.each에 테스팅할 반복되는 테스트의 인수들이 담긴 배열을 전달하고, 내부 함수에 테스트 로직을 작성한다. 이 경우, 같은 테스트 문구가 뜨기 때문에, 따로 테스트 하는 요소의 이름도 전달해 주고, %p를 통해, 각 테스트가 어떤 테스트를 하는 로직인지 구분할 수 있도록 해주었다.

사담

TDD 방식을 통해 프로젝트를 진행하는 것은 처음이어서, 진행이 훨씬 더딘 것 같다. 또한 중간중간에 테스트 코드의 수정을 많이 해야할 것 같다.

0개의 댓글