며칠간 고생을 마치며.
저의 App은
Next js
을 기반으로redux
로 상태관리를 하며redux-saga
를 통해 side-effects를 처리했습니다. 또한styled-component
와SCSS
를 사용하여 style을 처리했습니다.
나에게는 배포 직전 단계의 React 프로젝트가 있었다. 이미 완성된 App에, 어쩌면 불필요한 테스트를 나는 시도해보기로 했다.
jest
는 자바스크립트 테스팅 프레임워크고enzyme
은 리액트 테스트 라이브러리고.. 두가지를 같이 사용하면 편하다고?
묻고 더블로 가!
구글을 검색 내용처럼 npm i -D jest babel-jest babel-core enzyme enzyme-adapter-react-16
설치를 하고 설정파일을 적용했다.
나의 콘솔창은..
Unexpected token '<'
Unexpected token ' . '
could not find react-redux context value;
jest와 enzyme을 검색해보면 sum
함수를 만들고 기댓값(expect()
)이 matcher
함수 toBe()
와 같은지 비교하고 마무리하는 내용이 절반이다.
그렇게 단순하게 내가 생각한 시나리오대로 통과되고 pass
가 뜰 줄 알았다.
SCSS, Redux, Babel 등 다양한 의존관계를 포함하고 있는 통합적인 테스트였다.
따라서 그만큼 설정파일도 신경써야하고, 그 외의 기능을 사용하기 위해 필요한 준비가 많았을 뿐이다.
먼저 JS testing Framework인 jest
와 React test library인 enzyme
을 같이 사용하기 위해서 설정이 필요하다.
npm i jest babel-jest enzyme enzyme-adapter-react-16 enzyme-to-json identity-obj-proxy -D
jest와 enzyme을 설치한다. CRA(create-react-app
)일 경우 jest는 설치돼 있으니 CRA인 경우 설치하지 않는다.
identity-obj-proxy
는 css파일을 import해서 사용하는 사람에게 필요한 library이기 때문에 필요에 따라 설치하면 된다.
jest configuring페이지에도 나와있지만 jest.config.js로 설정하는 방법과 package.json에 설정하는 방법이 있다. 본인이 원하는 방식대로 하면 되지만 필자는 package.json에 설정할 경우 설정이 하나도 되지 않았다.
jest.config.js파일을 root폴더에 생성한다.
개발은 JS로만 한 탓에 typescript설정은 해당 링크를 참고하면 된다.
rootDir/jest.config.js
module.exports = { testPathIgnorePatterns: ['<rootDir>/.next/', '<rootDir>/node_modules/'], setupFilesAfterEnv: ["<rootDir>/enzyme.js"], moduleNameMapper: { "\\.(css|less|scss)$": "identity-obj-proxy" }, snapshotSerializers: ["enzyme-to-json/serializer"] };
style파일이 있을 경우 설치한 identity-obj-proxy를 moduleNameMapper로 설정하여, import한 css파일 등의 unexpected token '.'을 처리할 수 있다.
이후 setupFilesAfterEnv의 enzyme.js을 만들어주어야 한다.
이 파일은 해당 React버전에 맞게 enzyme을 사용할 수 있게 해주는 파일로서 해당 React버전에 알맞게 설치 후 아래와 같이 파일을 적용하면 된다.
rootDir/enzyme.js
import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; configure({ adapter: new Adapter() });
이전 항목에서 설정했다면 그 다음으로 넘어가도 된다.
설치 : npm i -D identity-obj-proxy
jest설정파일에 moduleNameMapper: { "\\.(css|less|scss)$": "identity-obj-proxy" }
를 넣어준다.
component에서 useSelector함수에서 오류를 내뱉는다. 또는 useDispatch함수에서 오류를 내뱉는 경우 이건 redux 때문이다.
먼저 redux-mock-store
을 사용하여 가짜 Store를 만들어 테스트할 수 있다. 이 store는 특정 액션의 dispatch의 여부를 판단할 수 있게해준다.
testPage에서
import configureMockStore from 'redux-mock-store'; const mockStore = configureMockStore(); // 아래와 같이 가짜 스토어를 만들 수 있다. let store = mockStore({ user: { id: 1, nickname: 'woogie' } });
이후 matcher함수를 통해 action을 테스트 할 수 있다.
이번에는 App내에서 redux
를 사용하기 위해 만든 실제 store를 활용하여 작업한다.
next와 redux를 함께 쓰기위해 사용하는 next-redux-wrapper는 HOC구조로 app을 감싸기 때문에 test.js파일에서 enzyme을 통한 component생성시 오류가 뜬다.
따라서 store를 생성하기 위해 만든 파일(ex: configureStore.js)에서 createStore부분만을 호출하여 해당 store를 Provider의 store props에 넣어주면 작동한다.
현재 store를 넣어주어 오류가 나지않고 눈물의 초록색 pass를 확인한 상황이다.
왜 Testing을 해야하는가에 대해 나름의 과정으로 알아가는 중이다. 처음에는 느낌이 오지 않았던 jest와 enzyme의 차이도, 왜 testing이 필요한지.. 안개가 걷혀가는 것 같다.
아마 testing을 했다면 개발시 서버를 돌려가며 웹브라우저에서 했던 나의 수고와 시간을 절반 넘게 줄였을 것 같다. 팀 개발이 아니라는 이유로 testing과정의 중요성과 효과를 과소평가했다. 이후 testing 글을 통해 test의 시나리오를 잘 구성하여 좋은 테스트 코드를 짜기위해 머리써봐야겠다.