[Next.js] 테스팅 도입기(2)- 테스트 작성 방법 및 단위

aeong98·2022년 3월 16일
0
post-thumbnail
post-custom-banner

1. 테스트 적용 방법

프론트엔드 테스트의 기본 개념과, 테스트 대상에 대한 설명입니다.

1-1. 테스트 종류 와 개념

유닛(Unit) 테스트

작은 단위로 작성되는 테스트

  • 컴포넌트가 잘 렌더링 된다.

  • 컴포넌트의 특정 함수를 실행하면 상태가 우리가 원하는 형태로 바뀐다.

  • 리덕스의 액션 생성 함수가 액션 객체를 잘 만들어낸다.

  • 리덕스의 리듀서에 상태와 액션 객체를 넣어서 호출하면 새로운 상태를 잘 만들어준다.

이렇게, 잘게 쪼낸 기능 단위의 테스트를 하면, 전체적으로 잘 작동하는지 확인하기 위해 통합 테스트를 진행합니다.

통합(Integrated) 테스트

기능이 전체적으로 잘 작동하는지 확인하기 위해 사용하는 것이 통합테스트

  • 여러 컴포넌트가 렌더링되고 서로 상호 작용을 잘 하고 있다.

  • DOM 이벤트를 발생 시켰을 때 우리의 UI 에 원하는 변화가 잘 발생한다.

  • 리덕스와 연동된 컨테이너 컴포넌트의 DOM 에 특정 이벤트를 발생시켰을 때, 우리가 원하는 액션이 잘 디스패치 된다.

2. 테스트 대상 및 방법

A. 리덕스 테스트
B. 컴포넌트 렌더링 테스트
C. 비동기 함수 테스트
D. Hooks

A. 리덕스 테스트

리덕스 부분에서 테스트 해야 되는 것들

  • 액션 생성 함수

  • 리듀서

  • 리덕스에 연결된 컴포넌트 : 컨테이너(Container) 컴포넌트

  • 리덕스에 연결되지 않은 컴포넌트 : 프레젠테이셔널(Presentational) 컴포넌트

**리덕스 테스트 예시 코드

import worst10, {initializeData, worst10Thunk} from '../../store/modules/worst10';
import { worst10MockData } from "../../__mocks__/dataMock";
import {api} from "../../api/api";
import store from "../../store/store";

describe("worst10 리듀서 테스트", ()=>{
    // api 호출 함수 모킹 
    beforeEach(async()=>{
        api.get=jest.fn().mockResolvedValue({
            data: worst10MockData,
        })
    });
    
    // 1. 초기 상태 테스트
    it("초기 상태 확인", ()=>{
        expect(worst10(undefined, {type: '@@INIT'})).toEqual({data:[{}], status:""})
    })
    
    // 2. 리듀서 테스트 
    it('초기화 액션 확인',()=>{
        let state= worst10(undefined, initializeData(worst10MockData.results));
        expect(state.data).toEqual(worst10MockData.results);
    })

    // 2-A. Thunk 리듀서 테스트 
    it('비동기 데이터 패칭 Thunk 확인',async()=>{   
        await store.dispatch(worst10Thunk({
            startDate:"2022-02-02",
            endDate:"2022-02-02",
            workingHour: "all"
        }))
        let state=store.getState().worst10;
        expect(state.data).toEqual(worst10MockData.results);
        expect(state.status).toEqual("success");
    });
    
    // 3. 컨테이터 컴포넌트 테스트
    it("API를 호출해서, 카드 컴포넌트를 렌더링 해야 한다.", async () => {
      await render(<CardListContainer></CardListContainer>);
      expect(screen.getByText("가동률 Worst 10")).toBeInTheDocument;
      expect(screen.getByText("최초 동작 Worst10")).toBeInTheDocument;
    });
})

B. 컴포넌트 렌더링 테스트

react-testing-library 사용 : 렌더링 결과를 테스트. 실제 화면에 무엇이 보여지는지, 그리고 어떠한 이벤트가 발생했을 때 화면에 원하는 변화가 생겼는지 이런 것을 확인하기에 최적화된 테스트

  • 컴포넌트 렌더링 테스트에서 해야되는 것들

  • 렌더링 테스트

  • 스냅샷 테스트 (사용 x)

  • 요소 확인

  • 이벤트 발생 후 화면 변화 테스트

**컴포넌트 렌더링 테스트 예시 코드

import React from "react";
import { render, screen, cleanup , fireEvent, RenderResult} from '../utils';
import Login from "../../components/login/Login";
import { findByText } from "@testing-library/react";

describe("로그인 페이지 테스트", ()=>{
    let container : RenderResult;
   
    // 1. 렌더링 테스트 
    beforeEach(()=>{
        container=render(<Login></Login>);
    })

    afterEach(cleanup);
    
    // 2. 요소 확인 테스트
    it('로그인 페이지 렌더링 테스트' , async()=>{
       expect(screen.getByText("GEC 스마트팩토리 모니터링 솔루션")).toBeInTheDocument;
    })

    // 3. 이벤트 발생 후 화면 변화 테스트
    it('로그인 입력 테스트', async()=>{
        const idInput :any= container.getByPlaceholderText("아이디");
        const passwordInput :any = container.getByPlaceholderText("패스워드");

        expect(idInput.value).toBe('');
        fireEvent.change(idInput, {target :{value :'admin'}});
        expect(idInput.value).toBe('admin');

        expect(passwordInput.value).toBe("");
        fireEvent.change(passwordInput, { target: { value: "admin123!" } });
        expect(passwordInput.value).toBe("admin123!");
    })

    it('로그인 입력 실패시', async()=>{
        const button = screen.getByText("로그인");
        
        fireEvent.click(button);

        expect(
          screen.getAllByText("가입하지 않은 아이디거나, 잘못된 비밀번호 입니다")
        ).toBeInTheDocument();
    });
}) 

C. 비동기 함수 테스트

REST API 를 호출해야 하는 컴포넌트일 경우, 테스트 코드에서 똑같이 요청을 보낼 수 있지만, 일반적으로 서버에 API 를 직접 호출하지 않고 이를 mocking 합니다.

mocking 이란 ?

단위 테스트 작성 할 때, 해당 코드가 의존하는 부분을 가짜 (mock) 으로 대체하는 기법. 실제로 서버에 API 연결해서 테스트를 진행하는 경우 DB나, 서버 와 같은 실제 인프라에 영향을 줄 수 있습니다. 따라서, 프론트엔드에서 할 수 있는 테스트 역할을 분리하기 위해 가짜 객체를 만들어서 테스트하는 모킹 기법을 사용합니다.

REST API 호출 비동기 함수 테스트 예시

import React from "react";
import {cleanup} from "../utils";
import {api} from "../../api/api";
import {Worst10API} from '../../api/api';
import {worst10MockData} from '../../__mocks__/dataMock';

describe("Worst10 페이지 테스트", ()=>{
    let spyGet:any;

    beforeEach(async()=>{
        // 1. api 호출 함수 모킹 
        api.get = jest.fn().mockResolvedValue({
          data: worst10MockData,
        });
    })

    afterEach(cleanup);

    it('모킹 API 테스트',async()=>{
        // 2. 비동기 함수 호출 
        const result= await Worst10API.yulkok(
            "2022-02-02",
            "2022-02-02",
            "all"
        );
        
        // 3. 호출 REST API 엔드포인트 확인
        expect(spyGet).toBeCalledTimes(1);
        expect(spyGet).toBeCalledWith(
          "api/example/8?beginDateTime=2022-02-02&endDateTime=2022-02-02&timeType=all"
        );
    })
})

참고 자료

profile
프린이탈출하자
post-custom-banner

0개의 댓글