본문 바로가기

TIL(Today i learned)

[TIL-2022.09.30] 테스트코드 작성의 어려움

1.알고리즘 스터디 : 

8시30분 - 9시30분까지 알고리즘 스터디를 진행 

 

2.오늘 가장 먼저 한 일은 테스트 코드를 작성하는 것 :

먼저는 멘토님께서 작성해주신 테스트코드 브런치를 합쳤더니, 테스트를 통과하지 못하는 것들이 발견되었다. 그래서 그 부분들을 먼저 수정했다. 

 

음... 이번에는 이런 에러를 만났다.

 진짜 테스트 코드 작성하는게... 뭔가 너무 어색하고 힘든 느낌이다. 우선 저 에러 문구를 보면, 내가 새롭게 작성한 내용중에 자바스크립트 문법에 어긋나는 것이 있나보다. 음.. 아니면 타입스크립트 때문에 뭔가 트렌스파일을 못하는 것인지. 우선 에러 문구 하단에서 안내해주는대로 타입스크립트와 관련된 설정들을 해주었다. 그래도 해결은 안되었다. 

 

여차여차해서 스택오버플로우를 찾았고, jest.config.js에 다음과 같이 설정해주었더니 해결되었다. 

uuid: require.resolve('uuid'),

https://stackoverflow.com/questions/73203367/jest-syntaxerror-unexpected-token-export-with-uuid-library

 

JEST - SyntaxError: Unexpected token 'export' with uuid library

I used to solve similar errors while I was using Jest with only Javascript but currently Im not able to do so with Typescript. All my tests were running fine until I installed Puppeteer which requi...

stackoverflow.com

우선 해결하긴 했는데, 사실 아직 어떻게, 왜 해결되었는지는 모르겠다. 이 문제를 해결한다고 걸린시간 40분..ㅜ 너무 오래 걸린것일까. 

 

3.폴더구조 고민 : 

폴더 내부를 index.tsx로할지, 컴포넌트의 이름으로 할지 고민이다. 무엇이 더 좋을까? Indext.tsx로하면 import할 때 폴더이름만 적어주면된다. 그런데, 컴포넌트 이름으로하면 import할 때 해당컴포넌트 이름을 한번 더 적어줘야 한다. 예를 들어 Button이라고 할 때, 

import * from "./components/Button/Button"

과 같은 방식이 되는 것이다. 사실 Button이라는 이름으로해도, 이런 방식으로 import하지 않을 수 있다. 지금과 같이 두번 적어줘야하는 이유는 내가 폴더안에다가 컴포넌트를 넣어주고 있기 때문이다. 폴더를 굳이 생성해준 이유는 해당 컴포넌트 바로 옆에서 테스트 코드를 작성해주고 싶었기 때문이다. 바로 옆에서 테스트코드를 확인할 수 있으니까 그게 좋은 것 같았다. 

만약 폴더를 생성하지 않고 컴포넌트를 파일로 그대로 만들어버리면, 테스트코드 폴더를 따로 만들면 된다. 그렇게하면 파일이름을 컴포넌트 이름으로하면서 import할 때 이름을 두번 넣어줘야하는 일도 없어진다. 

 

굳이 Index.tsx로 하지 않겠다고 생각했던 것은, 다른 개발자가 볼 때 불편하지 않을까 싶은 생각 때문이었다. 음... 그런데 사실 생각해보니까, index로 적혀있는 부분은 바로 옆에 있는 파일의 경우에만 index로 표시되지, 하나만 폴더를 건너가면 컴포넌트 이름을 바로 알 수 있다. 

 

아무래도 import할 때 글자를 두개 적어주지 않아도 된다는 점, 그리고 테스트 코드 파일을 해당 컴포넌트 바로 옆에 위치해둘 수 있다는 점을 고려했을 때, index.tsx로 그대로 가는 것이 좋을 것 같다. 다른 개발자의 가독성 또한 폴더 하나만 건너띄면 문제가 없어진다. 

 

 

아, 근데 한가지 더 생각났다. 여러개의 파일을 띄워놓고 작업을 할 때, 이렇게 Index로 되어있으면 좀 불편한 점이 있는 것 같다. 음... 쉽지 않네. 

아무래도 테스트코드 관련 폴더를 따로 만들고, 컴포넌트들에 대해서는 폴더를 따로 만들지않고 바로 파일이름으로 하는 것이 좋을 수도 있을 것 같다. 

 

4.button 클릭 테스트코드 작성 : 

WritePage 내부에 button이 있다. 이 버튼을 클릭했을 때의 동작에 대해서 테스트 코드를 작성해야 한다. 

...
const handleOpenModal = () => {
    setOpen(!isOpen);
  };

  return (
    <>
      {isOpen && (
        <CreateArticleModal
          handleOpenModal={handleOpenModal}
          articleElements={articleElements}
        />
      )}
      <button onClick={handleOpenModal}>생성하기</button>
...

이렇게 작성된 컴포넌트가 있다. 현재 button에 등록되어있는 함수는 부모에서 따로 받아오는 함수가 아니다. 컴포넌트 내부에서 가지고 있는 함수다. 이런 함수의 경우에는 어떻게 테스트해야하는 것일까? 보통의 예시들은 외부에서 해당 함수를 모킹해서 자식으로 넘겨주고, 그것이 클릭되었는지를 테스트하는 방식으로 이루어진다. 지금은 다르다. 

https://stackoverflow.com/questions/60916736/how-to-mock-a-function-and-expect-it-to-be-called

 

How to mock a function and expect it to be called?

I am new to react-testing-library and I have been trying to test one function for a long time. for example, I want to check if when a button is clicked a given function is called and it's throwing ...

stackoverflow.com

조금 검색을 해보니 위와 같은 자료를 찾을 수 있었다. 답변들 중 채택된 답변은, 함수를 모킹하는 방법을 알려주지 않고, 테스트를 다른 방향으로 해보라고 조언하고 있는 것 같다. 그 아래에 있는 답변이 모킹하는 방법을 알려준다. 나는 그 아래에 있는 방법으로 해보려고 한다. 음.. 아래 방법으로 해보려고 했는데, 아래의 방법은 enzyme의 방법이었다. 어쩐지 추천을 많이 받지 못한 것 같았다. 질문자는 react-testing-library를 질문하고 있는데, enzyme을 활용한 대답을 알려준다. 

진짜 테스트코드는 매번 작성할 때마다 계속 병목에 걸린다. 그래서 너무 암이다... 이게 계속 반복되다보면 테스트코드가 두려워지게 되는 것 같다. 언제 이 테스트코드를 작성하는 것이 뚫릴 수 있을까. 뭔가 이미 코드베이스가 있으면 기존에 있던 코드들을 보면서 참고하면 좋을 것 같은데, 애매하다ㅜ

 

그래서 다시 방향을 바꿔서 클릭이 되었는지를 테스트하는 것이 아니라, 클릭 했을 때 원하는 결과를 테스트하기로 했다. 내가 원하는 결과는 모달이 화면에 나오게 되는 것. 그래서 모달에 testid를 부여하고 테스트를 진행했다. 그런데 testid를 가진 컴포넌트를 찾을 수 없다고 한다. 무슨일일까?혹시 모달이 올라갈 수 있는 modal_root div가 없기 때문에 그런것은 아닐까 하고 추측해보았다. 그래서 

  const renderWritePage = () =>
    render(
      <>
        <div id="modal_root" />
        <WritePage />
      </>,
    );

이렇게 수정해주었는데, 그래도 안된다.  이런저런 방법을 찾다가 알게 된 것은 내가 testid를 잘못된 위치에 부여하고 있었던 것이다. 처음에는 아래와 같이 page 컴포넌트에서 그대로 testid를 부여해주었었다. 

      {isOpen && (
        <CreateArticleModal
          data-testid="createAritcleModal"
          handleOpenModal={handleOpenModal}
          articleElements={articleElements}
        />
      )}
      <button onClick={handleOpenModal}>생성하기</button>
      <TitleInput onChange={setTitle} placeholder="제목을 입력해주세요." />

이렇게해도 잡히지 않기에, CreateArticleModal 안쪽에 있는 요소에 testid를 부여해보았다. 

   <Modal handleOpenModal={handleOpenModal}>
      <>
        <ButtonWrapper data-testid="createArticleModal">
          <Button
            label="취소"
            buttonType="secondary"
            onClick={handleOpenModal}
          />
          <Button
            label="저장"
            buttonType="primary"
            onClick={() =>
              createArticle({ ...articleElements, imgUrl, description })
            }
          />
        </ButtonWrapper>
        <Guide>대표이미지 선택</Guide>
        <ImageUpload setImageUrl={setImgUrl} />
        <Guide>태그를 선택하세요.</Guide>
        <DescriptionInput onChange={setDescription} />
        <Guide>설명글을 작성해주세요.</Guide>
      </>
    </Modal>

이렇게. 그런데 이제는 잡힌다. 다행이다. 테스트를 통과했다... ㄷㄷ

 

jest-dom을 테스트할 때 예시코드들이 적혀있다. 필요할 때마다 참고하면 좋을 것 같다.

https://github.com/testing-library/jest-dom#tohaveformvalues

 

GitHub - testing-library/jest-dom: Custom jest matchers to test the state of the DOM

:owl: Custom jest matchers to test the state of the DOM - GitHub - testing-library/jest-dom: Custom jest matchers to test the state of the DOM

github.com

 

 

5.계속 테스트코드 작성 : 

WritePage에 대한 테스트코드를 작성하고 나서, 갑자기 조금, 아주 조금 감이 잡혔다. 그래서 신나게 Modal 컴포넌트, CreateArticleModal 컴포넌트, ImageUpload 컴포넌트에 대한 테스트코드를 작성했다. 

ImageUpload 컴포넌트를 작성하는 와중에도 느낀 것이지만, 그 내부에서 useState를 사용하고 그것이 동작에 영향을 미칠 때 테스트하는 것이 아직까지 애매하게 느껴지는 것 같다. 

 

 

6.vercel cli가 갑자기 사라졌다 : 

nvm의 버전이 계속 바뀌었었다. 그래서 nvm 의 default를 현재 안정된 버전인 16.17.1로 변경시켜주었다. 그런데 vercel cli를 실행하려고 하니 실행이 안되는 것이다. 16.5.0 버전에 설치가 되어있었나보다. 솔직하게 아직 이것의 구조가 어떻게 되어있는 것인지 모르겠다. 잠시 nvm use 16.5.0로 바꾸고 다시 vercel cli를 실행해봤더니, 오 실행이 잘된다. 내가 사용하고 있는 node 버전에 vercel cli가 전역적으로 설치되어 있는 것 같다. 

그러면 vercel cli를 16.17.1버전에도 설치해줘야하는 것인가? 만약에 내가 또 nvm을 통해서 node의 버전을 또 바꾸면? 그러면 또 글로벌하게 사용되는 cli들을 다시 설치해줘야하는 것일까? 이것을 이해하기 위해서는 무엇을 찾아봐야하는 것일까? 

 

 

 

7.vercel에 배포하는데, TypeError: Cannot read property 'II' of undefined 가 나왔다 : 

에러 문구

어디서 발생한 에러인지 들어가보니, 다음과 같은 부분이었다.

에러가 발생한 위치

현재 컴포넌트 내부에서는 아래와 같이 작성하고 있는 중이었다. 

const DescriptionInput = styled(Input)``;

이전에는 잘만 배포가 되다가 지금은 문제가 되었다. 이전에는 Input 컴포넌트에서 가져오는 부분이 

import { Input } from 'src/components/common';

이렇게 되어있었다. 현재는 

import { Input } from 'src/components';

이렇게 바꿔주고, src/components의 index.ts에서는 

export * from './common';

이렇게 사용하고 있었다. 이중으로 가져오도록 설정이 되어있었는데, 이렇게 하니까 swc에서 빌드할 때 뭔가 문제가 생기는 것 같다.  아 그리고 단순히 import해오는게 문제가 아니라, 이렇게 import해온 친구를 emotionjs에서 사용할 때, (Input)이렇게 감싸서 사용하면 문제가 되는 것 같다. 그래서 아직은 DescriptionInput이 정의내려져 있지 않기도 하고, 그냥 Input을 바로 사용하기로 했다. 

 

 

import 관련된 문제는 위의 문제를 해결했음에도 계속해서 나오고 있었다. 뭔가 해결을 하려고 이것저것 시도를 해보았지만, 별다른 성과가 없었다. 조금 검색해서 아래와 같은 문서를 찾았다.

https://vercel.com/guides/how-do-i-resolve-a-module-not-found-error

 

How do I resolve a 'module not found' error?

Information on resolving a 'module not found' error.

vercel.com

문서를 읽다보니 생각난 것인데, 아무래도 Common이라고 컴포넌트이름을 가지고 있다가, common으로 소문자로 이름을 바꿨더니 인식을 제대로 못하는 것 같다. 

vercel 문서에서 소개하고 있듯이

git config core.ignorecase false

를 적용해봤다. 그럼에도 아직도 잘 되지 않는중이다. 오히려 뭔가 더 꼬이는 기분이다. 

위에 깃 명령어를 적용시키고 난 후  배포를 해보니, 에러문구가 이번에는 조금 더 다르게 나왔다. 확실히 이번에는 Common과 common의 차이라고 분명하게 말해주는 듯하다. 

 

아무래도 대소문자를 인식못하는 것 같으니까, 그냥 아예 ui로 폴더이름을 바꿔버렸다. 그랬더니 해결. 임시로 ui로 변경해두었다가, 나중에 다시 common으로 변경시키면 될 것 같다. 

 

8.react 18 블로그 번역 : 

딱 15분 시간을 재고 15분만 번역 작업을 했다. 내일은 15분씩 2번. 30분 정도 해볼까. 

 

 

9.titleInput 컴포넌트 작성 : 

제목 입력창인데, 먼저 테스트코드를 작성한 다음 제목컴포넌트를 작성해봤다. TDD를 해본셈이다. 음. 그런데 Input에서는 잘 동작하던 onChange를 체크하는 테스트코드가 통과를 못하고 있다. 진짜로.. 테스트코드 작성하는거 너무 힘들다. 뭔가 그냥 "딱 이거 배우면 사용할 수 있다." 이런개념을 넘어서는 것 같은 기분이다. 다양한 케이스가 많고, 아직 나로써는 종잡을 수가 없다. 테스트코드 때문에 거의 시간이 다 가는 것 같다. 테스트 코드만 아니었어도, 진작에 더 많은 기능을 만들었을텐데 하는 생각이 들긴한다ㅜㅜ 그래도. 어렵다고 그만두는건 정말 싫다. 진짜 간단한 제목 입력창 하나 만드는데도 벌써 시간이 1시간이나 지나가버렸다...🤯🤯🤯 

 

테스트 코드 관련된 공부를 조금 더 해야할 것 같다. 찾아보니 튜토리얼 문서가 있다. 이 문서는 공식문서에서도 소개하는 사이트다. 

https://www.robinwieruch.de/react-testing-library/

 

React Testing Library Tutorial

Learn how to use React Testing Library in this tutorial. You will learn how to test your React components step by step with unit and integration tests ...

www.robinwieruch.de

 

https://www.daleseo.com/react-testing-library/

 

React Testing Library 사용법

Engineering Blog by Dale Seo

www.daleseo.com

이 문서도 있었는데, 여기서 소개하는 내용은 비교적 쉽다. 여기서 소개하는 수준 정도는 나도 이미 알고 있는 듯 하다. 

 

 

갑자기 생각나서 react testing library example을 검색해봤다. 그랬더니 kent가 직접 만들어둔 examples가 있다. 하루에 2개씩만 읽고 분석해보자. 아직은 테스트코드를 작성하는게 많이 익숙하지 않은데, 계속해서 부딪히다보면 분명히 테스트코드를 작성하는게 너무 자연스럽고 쉽게 느껴지는 순간이 올 것이다. 더 나아가서 어떻게하면 테스트 코드를 '잘'작성할 수 있는지 고민하는 순간이 곧 올 것이다. 

https://codesandbox.io/s/github/kentcdodds/react-testing-library-examples?file=/src/__tests__/async.js 

 

react-testing-library-examples - CodeSandbox

A repo full of examples of how to use react-testing-library and test your react components

codesandbox.io

 

시간이 늦었다. 내일 일어나서 다시 test 코드와 관련된 자료도 좀 읽고, 다시 코드를 작성해봐야겠다.