2. 프로젝트 준비하기
우선, 우리가 테스트를 진행 할 프로젝트가 필요하겠죠. 테스트용 프로젝트를 만드는 시간이 아까우니, 제가 미리 준비해놓은, 이전의 튜토리얼 테스트에서 진행했던 프로젝트에 리덕스를 적용시킨 코드를 사용하여 구현해보겠습니다.
$ git clone https://github.com/vlpt-playground/react-test-tutorial.git
$ git checkout redux-testless
튜토리얼이 진행되기 전에 이전에 프로젝트에서 어떠한 변화가 있었는지 간단하게 짚고 넘어가겠습니다.
- NameForm, Counter, App 컴포넌트에서 더 이 상 state 를 사용하지 않게 됐습니다.
- 위에 따라, 해당 컴포넌트들의 테스트 코드들 또한 스냅샷만 찍도록, 수정해주었습니다.
- API 요청을 통해 받아온 데이터를 보여줄 Post 컴포넌트를 만들었습니다.
- 리덕스 모듈 세가지: counter, names, post 를 만들었습니다.
- 리덕스 스토어 생성 할 땐, thunk 미들웨어를 적용해주었습니다.
- 이에 따른 세가지 컨테이너 컴포넌트: CounterContainer, NamesContainer, PostContainer 가 만들어졌습니다.
우리가, 상태 관련 로직을 리듀서쪽으로 올길 것이기에, 기존에 작성했던 테스트 함수들을 대부분 날려주었습니다.
계속 진행하기전에, 각 리덕스 모듈들이 어떠한 역할을 하는지 알아보겠습니다.
store/modules/counter.js
const INCREASE = 'counter/INCREASE';
const DECREASE = 'counter/DECREASE';
export const increase = () => ({ type: INCREASE });
export const decrease = () => ({ type: DECREASE });
const initialState = {
number: 0
};
export default function counter(state = initialState, action) {
switch (action.type) {
case INCREASE:
return { number: state.number + 1 };
case DECREASE:
return { number: state.number - 1 };
default:
return state;
}
}
단순히, INCREASE, ACTION 액션에 따라 number 값을 더하고, 빼줍니다. 이 모듈에서는, createAction 을 사용하지 않고 액션 생성함수를 직접 작성해주었습니다.
store/modules/names.js
import { createAction, handleActions } from 'redux-actions';
const CHANGE_INPUT = 'names/CHANGE_INPUT';
const INSERT = 'names/INSERT';
export const changeInput = createAction(CHANGE_INPUT, input => input);
export const insert = createAction(INSERT, name => name);
const initialState = {
input: '',
names: []
};
export default handleActions({
[CHANGE_INPUT]: (state, { payload: input }) => ({
...state,
input
}),
[INSERT]: (state, { payload: name }) => ({
...state,
names: state.names.concat(name),
})
}, initialState);
이 모듈에는 두가지 액션이 있습니다. 하나는, 인풋 값을 수정해주는 것이고, 또 하나는 names 배열에 새 아이템을 넣어주는 것 입니다. 불변성을 유지해야 하기에, concat 을 사용해주었습니다.
store/modules/post.js
import { createAction, handleActions } from 'redux-actions';
import axios from 'axios';
function getPostAPI(postId) {
return axios.get(`http://jsonplaceholder.typicode.com/posts/${postId}`);
}
const GET_POST_PENDING = 'post/GET_POST_PENDING';
const GET_POST_SUCCESS = 'post/GET_POST_SUCCESS';
const GET_POST_FAILURE = 'post/GET_POST_FAILURE';
export const getPost = (postId) => async (dispatch) => {
dispatch({ type: GET_POST_PENDING });
try {
const response = await getPostAPI(postId);
dispatch({ type: GET_POST_SUCCESS, payload: response });
return response;
} catch (e) {
dispatch({ type: GET_POST_FAILURE, payload: e });
}
}
const initialState = {
fetching: false,
error: false,
title: '',
body: '',
};
export default handleActions({
[GET_POST_PENDING]: (state) => ({ ...state, fetching: true, error: false }),
[GET_POST_SUCCESS]: (state, { payload: { data } }) => ({ ...state, fetching: false, title: data.title, body: data.body }),
[GET_POST_FAILURE]: (state) => ({ ...state, fetching: false, error: true })
}, initialState);
비동기 액션을 관리하기 위해서 여러가지 미들웨어들이 있습니다. 그 중 가장 기본적이라고 볼 수 있는 thunk 를 사용하여 jsonplaceholder 에 API 요청을 처리해주었습니다. 우리는 나중에, Post 컴포넌트 내부에 있는 LoadMe 가 적혀있는 버튼을 누르면 이 API 를 요청하고, 화면에 뿌려주도록 하겠습니다.
각 모듈들이 어떤 형식으로 작성하는지 감이 잡히시나요? (잘 모르겠다면, 아마, 리덕스쪽 코드를 조금 복습해야 할 것 같습니다.)
그럼, 슬슬 각 기능들을 위한 테스트 코드를 작성해주겠습니다.