정신을 차려보니 1,000개의 테스트가 있었다

징그러운 Jest 와 험난한 고난기와 애증의 관계 그 어딘가쯤에 위치한 영혼들을 위하여

MJ Studio
MJ Studio

--

나 테스트 1,000 개 짰다

저는 리액트 네이티브 개발자입니다. 저도 정신을 차려보니 이런걸 개발하고 있어서 어쩌다 이런 직업을 갖게 되었는지는 모르겠지만 일단 모바일 앱을 만드는 일을 합니다. 최근 정신을 차려보니 테스트케이스가 1000개가 넘어 자축과 노하우 공유와 험난했던 여정을 회고하고자 글을 써보려합니다.

일단… 테스트 파일은 총 144개고 테스트 케이스는 총 1001개고 CodeCov 가 계산해준 전체 프로젝트의 coverage는 93.29% 군요.

왜 테스트를 그렇게 많이 짰나요?

저는 사람을 안믿습니다. 성악설 이런게 아니라 사람이 어딘가에서 실수할 여지가 무한하다는 것을 믿습니다. 그나마 다행인건 제가 이 프로젝트는 혼자 개발을 한다는 점입니다. 믿지못할 사람이 한명(저)밖에 없으니 걔만 갈구면 됩니다. 개발을 하다보니 이분이 경악을 금치못할 실수를 많이 하시더군요. 그 실수 리스트를 나열하기엔 Medium의 글자수 제한을 경험할지도 모를 일이니 잠시 접어두도록 하겠습니다.

개발은 과거의 믿지못할 나와 현재의 이성적인(라고 믿는) 내가 싸우는 숨막히는 일자리 삭빵전입니다. 과거의 나에게 지고 실수를 하면 욕얻어먹고 일자리 삭제되는거죠. 재밌는건 과거의 나는 패널티가 없는데 나만 있습니다. 과거의 누군가가(아마 내가) 탄생시켜버린 코드라고 형용하기도 괴랄하고 무서운 그 무언가가 자꾸 내 발목을 붙잡으면 그순간에 프로젝트를 갈아엎으시길 추천드립니다.

여하튼 제가 지금까지 한 얘기는 테스트 코드가 있어야 코드를 더 깔끔하게 짤 수 있고 필요한 기능이 생기면 빨리 붙일 수 있고 뭐 유지보수성 따위가 좋아진다는 클린코드식 저명하고 따분한 이야기였습니다. 조금 제 식으로 풀어서 써봤네요. 물론 이런 재미없는 이야기를 하려고 이 글을 쓴건 아닙니다. 그런것을 원하시면 제가 예전에 쓴 글이 한 있는데 읽어보심을 추천드립니다.

리액트, 자바스크립트 테스트 뭘로 짜셨나요?

리액트는 JavaScript로 개발을 합니다. 구체적으로 말하자면 TypeScript도 덧붙일 수 있고 Flow도 쓸 수 있고 사실상 JavaScript가 아니라 JSX(JavaScript-XML) 일 수도 있고 그냥 개발자 지멋대로 개발하면 됩니다.

각 언어와 프레임워크마다 가장 인기있는 테스트 라이브러리들이 있는데, 자바스크립트 진영에서는 Jest를 주로 사용합니다. 역시 구체적으로 말하자면 babel-jest, jest-circus, jest-fetch-mock, jest-styled-components, ts-jest, @types/jest, @testing-library/jest-native, @testing-library/react-hooks, @testing-library/wreact-native, detox 등이 모두 프로젝트에서 지할일을 하고있지만 결국 Jest가 그 근간이 된다는 것은 변하지 않죠.

Jest 가 해주는 일은 사실 많지 않습니다. 함수가 뱉어내는 값이 우리가 원하는 값과 일치하는지, 해당 함수가 몇번이나 어떤 인자로 호출되었는지, 더 나아가서는 모듈 몇개 바꿔치기 해주는게 전부입니다. document도 깔끔하죠.

it('더해질 지어다', () => {
expect(1 + 2).toBe(3); // 이 테스트가 실패한다면 전 1000개를 다 지우겠습니다
});
더해졌다

테스트 코드 잘짜는 법이 있나요?

테스트 코드 잘짜는 법은 수도없이 많습니다. 실제로 외국의 유명한 IT기업에서는 테스트 코드만 보고 이 프로그램이 어떤 동작을 하는지 유추하는 면접 문제도 나온다고 합니다. 그만큼 테스트 코드를 잘짜면 프로젝트의 얼개도 쉽게 파악을 할 수 있다는 뜻이겠죠.

저는 Jest 얘기를 했으니 언어 한정적인 이야기를 좀 하려고 합니다. Jest 테스트를 짤 때 가장 잘 알고 있어야하는 것은 자바스크립트의 특성입니다.

자바스크립트에선 한 파일을 모듈이라고 부르는데, 이 모듈의 require나 ES6의 import 들이 얽혀있을 때 초기화되는 순서를 제대로 파악하지 못하면 그 테스트는 왜 실패하는 지 이유도 모른체 실패하기 십상입니다. 아니면 이것만 돌리면 성공하는데 저거랑 같이돌리면 실패하기도 하죠. jest.mock 이 어떻게 동작하는 지와 jest.resetModulesjest.spyOn 등 여러 유틸리티를 잘 쓸 수 있으면 좋습니다. 그 전에 자바스크립트의 monkey patch가 왜 가능한지에 대해서 탐구를 하면 좋습니다. 이건 다른 언어와 다른 자바스크립트 테스트를 작성하는 데 엄청난 매력이죠. 지멋대로 mock을 아무데서나 할 수 있으니까요.

또한 자바스크립트에서는 PromisesetTimeout, setInterval들이 어디서 어떻게 누가 동작시켜주는건지,

setTimeout(() => {
console.log(1)
}, 0)
console.log(2)

에서 왜 2가 1보다 먼저 출력되는건지 잘 파악해야 합니다. 비동기 작업의 흐름을 제대로 파악하지 못하면 비동기를 테스트하는 테스트코드에서는 당연히 혼란에 빠집니다. 이와 관련해서 좋은 리퍼런스를 남깁니다.

TDD 좋아하세요?

아니요. 저 TDD 안좋아합니다. 1000개의 테스트 코드중 950개는 이미 짠 코드를 테스트해보려고 작성한거고 TDD 흉내좀 내본건 한 30개 있는것같습니다. 저는 개발을 혼자해서 깃허브나 깃브랜치나 하물며 테스트 방식조차도 그냥 기분따라 커밋하고 머지하고 짜는편입니다. 굳이 쓸 필요를 못느꼈는데 어딘가에서 개발의 신이 나타나 내일부터 쓰라고 하면 한두번 더 써볼 생각은 있습니다.

자랑할만한 테스트 코드가 있나요?

그 전에 이짧은 동영상을 한번 봐주세요.

랜딩 페이지부터 아이디와 비밀번호를 치고 로그인을 해서 홈화면으로 가는 Flow입니다. 만약 제가 이러한 Flow를 테스트 코드로 검증을 해보고싶다고 하면 어떻게될까요?

it('Landing -> SignIn -> SignInEmail -> Home, Id로 로그인 성공, API 응답의 수능 성적이 나타남', async () => {
const mockReportEntity = MockGenerator.fetchReportEntity();

mockApi(AuthAPI, 'loginWithId', { token: 'token', user: UserAdapter.toDTO(MockGenerator.user()) });
mockApi(ReportAPI, 'fetchReport', FetchReportResponseAdapter.toDTO(mockReportEntity));
mockApi(DemoExamAPI, 'fetchRecommendedAndOngoingExams', { ongoing: { exams: [] }, recommended: { exams: [] } });
mockApi(DemoExamAPI, 'fetchCompletedExams', { exams: [] });

await navigator.navigate('Landing', 'Home');

await testingLib.waitExpectExistByText(mockReportEntity.nextExamName);
});

이렇게 짜면 됩니다.

API를 가짜 응답만 하게하는 코드가 4줄이고 실질적인 코드는 3줄입니다. 이런 코드를 짜기 위해서는 또 재미없는 클린 코드의 한소절을 인용해야 합니다.

테스트 코드를 위한 유틸리티를 만들어라

실제로 이렇게 적혀있는지는 기억이 안납니다만 아마 비슷하게 써있을겁니다. 그 책은 지금 제 모니터 받침대로 요긴하게 쓰이고 있어서 빼서 읽으면 모니터 높이를 다시 조절해야하는 대참사가 일어나기 때문에 굳이 그러진 않겠습니다.

여하튼 제가 수도없이 많은 테스트 유틸리티를 만들었다는 겁니다. 저는 실제로 리액트 네이티브 테스트 라이브러리의 열약한 지원환경때문에 테스트 라이브러리를 아예 교체르 해버려야 했던 상황도 있었는데 이러한 조언덕분에 테스트코드들을 손쉽게 다시 살려놓을 수 있었습니다. 감사합니다 모니터 받침대.

글을 마치며

알고리즘 공부를 하다 멘탈이 나가 두서없이 쓴 글이지만 한편으론 뿌듯합니다. 몇달전에 let과 const도 몰랐던 제가 이렇게 자바스크립트 테스트관련 글을 쓰고있다는게 묘한 감정입니다. 오랜만에 글을써 가벼운 글로 왔다갑니다.

읽어주셔서 감사합니다.

--

--