본문 바로가기

프로그래밍 독학/Jest

jest - redux 테스트하기 번역

반응형

https://redux.js.org/usage/writing-tests 번역입니다.

 

배우게 될 것

- 리덕스 사용 앱 테스트 추천 예제

- 테스트 설정 및 세팅 예시

 

가이딩 원리

테스트가 당신의 소프트웨어와 닮아갈 수록 당신에게 자신감을 안겨줄 것이다. - Kent C. Dodds

 

대부분의 Redux 코드가 순수 함수라서 모킹 없이 테스트하기 쉽습니다. 그러나 당신의 Redux 코드가 그것만을 위한 테스트를 필요로 하는지는 고려해야 합니다. 대다수의 시나리오에서 end-user는 리덕스가 사용되는지 전혀 알지 못하고, 신경도 쓰지 않습니다. 이처럼 Redux 코드는 많은 상황에서 명시적 테스트 필요없이 앱의 디테일의 구현으로 취급될 수 있습니다.

 

Redux 사용 앱을 테스트할 때 우리의 일반적 조언은:

 

- 함께 동작하는 모든 것들을 통합하는 test를 선호하십시오.

Redux를 사용하는 React 앱은 실제 스토어 인스턴스와 함께 Provider를 렌더합니다. 페이지 상호작용 테스트는 실제 Redux 로직을 사용해야 합니다. 앱 코드가 바뀔 필요 없도록 API 요청들이 모킹된 상태로 말이죠. 그리고 그 UI가 적절히 업데이트 되었는지 assert해야 합니다.

- 필요하다면 특별히 복잡한 reducer나 selector 같은 순수 함수를 위해 베이직 유닛 테스트를 사용할 수도 있습니다. 그러나 많은 경우에 그것들은 그냥 통합 테스트에 의해 처리되는 디테일을 구현한 것일 뿐입니다.

- selector 함수 혹은 React-Redux hooks를 모킹하려하지 마세요! 라이브러리에서 임포트된 모킹은 깨지기 쉽고 실제 앱 코드가 작동하는 것에 대한 자신감을 주지 않습니다

 

테스트 환경 세팅하기

 

Test Runner

Redux는 어느 테스트 러너로도 테스트될 수 있습니다. 그냥 순수한 Javascript이기 때문이에요. 근데 Jest를 많이 써요.(의역으로 생략)

 

전형적으로, 테스트 러너는 Javascript, Typescript 구문을 컴파일하기 위해 설정을 필요로 합니다. 당신이 UI 컴포넌트를 테스트할 예정이라면 테스트 러너가 mock DOM 환경에 JSDOM을 제공하도록 설정해야 합니다.

이 페이지의 예시들은 당신이 Jest를 사용하고 있다고 가정하고 있습니다. 그러나 당신이 어떤 테스트 러너를 쓰더라도 같은 패턴들이 적용됩니다.

 

전형적인 테스트 설정 문서를 참고하세요.

 

Configuring Jest · Jest

The Jest philosophy is to work great by default, but sometimes you just need more configuration power.

jestjs.io

 

UI, 네트워크 테스팅 툴

Redux 팀은 Redux에 연결된 리액트 앱을 테스트할 때 React Testing Library를 사용하는 것을 추천합니다. React Testing Library는 좋은 테스트 경험을 선사하는 간단하고 완전한 React DOM 테스팅 유틸리티입니다. 그것은 ReactDOM의 render 함수 그리고 react-dom/tests-utils의 act 함수를 사용합니다. 이 테스팅 라이브러리 툴 패밀리는 많은 다른 인기 있는 프레임워크에도 적용할 수 있습니다.

 

 

jest-dom | Testing Library

jest-dom is a companion library for Testing Library that provides custom

testing-library.com

 

연결된 컴포넌트들과 리덕스 로직 통합 테스트

Redux가 연결되된 React 컴포넌트들을 함께 동작하는 모든 것들을 통합테스트로 테스트하는 것을 추천합니다. 주어진 상황에서 사용자가 상호작용할 때 앱이 당신이 의도한대로 동작하는 걸 확인하기 위한 assertion들과 함께요.

 

예시 앱 코드

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import { userAPI } from './userAPI'
import type { RootState } from '../../app/store'

export const fetchUser = createAsyncThunk('user/fetchUser', async () => {
  const response = await userAPI.fetchUser()
  return response.data
})

interface UserState {
  name: string
  status: 'idle' | 'loading' | 'complete'
}

const initialState: UserState = {
  name: 'No user',
  status: 'idle'
}

const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {},
  extraReducers: builder => {
    builder.addCase(fetchUser.pending, (state, action) => {
      state.status = 'loading'
    })
    builder.addCase(fetchUser.fulfilled, (state, action) => {
      state.status = 'complete'
      state.name = action.payload
    })
  }
})

export const selectUserName = (state: RootState) => state.user.name
export const selectUserFetchStatus = (state: RootState) => state.user.status

export default userSlice.reducer
반응형

'프로그래밍 독학 > Jest' 카테고리의 다른 글

jest 시작하기 - jest의 개요  (0) 2023.06.22
Jest Mocks에 대한 이해  (0) 2021.05.20
Jest 웹팩과 함께 쓰기  (0) 2020.12.17