본문 바로가기
Project/Pennyway

코드 가꾸기 - 테스트 코드

by 이의찬 2024. 7. 9.

1. Why?

프론트엔드에서 테스트 코드를 작성하는 비율은 상대적으로 높지 않다. 삼성청년SW아카데미 내에서 3차례 프로젝트를 진행하며 그 때마다 10팀 씩, 총 30팀을 봤지만 한 팀도 테스트를 도입하지 않았다. 심지어는 현업에서도 테스트 코드를 작성하지 않는 경우를 보기도 했다.

 

하지만 테스트 도입에 대해서 고민하면서, 그리고 직접 테스트 코드를 작성하면서 느낀 것은 보통 테스트를 작성할때의 비용이 테스트를 작성하지 않았을 때의 비용에 비해 훨씬 적다는 것이다. 프론트엔드에 관심이 많은 학생이라면, 이 글을 읽고 테스트에 대해 관심을 가지게 되면 좋겠다.  


2. 코드를 가꿔야하는 이유

<Pennyway>는 내가 진행한 프로젝트 중 테스트를 도입한 첫 프로젝트이다. 정확히는 Mock API를 사용한 비즈니스 로직 테스트와 기능 테스트를 도입했다.

 

GitHub - CollaBu/pennyway-client-webview: 🪙 Pennyway Webview Client: A web browser that is embedded in a pennyway iOS mobile

🪙 Pennyway Webview Client: A web browser that is embedded in a pennyway iOS mobile client - CollaBu/pennyway-client-webview

github.com

테스트란?

소프트웨어 프로젝트의 지속 가능한 성장을 가능하게 하는 것
- 단위 테스트(책)

 

위의 정의에서 눈여겨 보아야 할 것은 '지속 가능한 성장'이다.

 

대부분의 학생들과 취준생들, 즉 실제 상품을 시장에 배포하고 유지해보지 못한 사람들은 '지속 가능'의 중요성을 잘 알지 못한다. 왜냐하면 그들(나 포함)의 프로젝트들은 보통 다음의 과정에 따라 진행되기 때문이다.

  1. 기획한다.
  2. 개발한다.
  3. 배포할 수도 있고, 하지 않을 수도 있다. 그리고 다른 프로젝트로 넘어간다.

이렇게만 프로젝트를 진행하기에, 배포 이후의 과정인 '유지 보수'를 경험할 수 없다.

 

하지만 시장의 상황은 계속해서 바뀔 것이고, 이에 따라 유저에게 가치를 제공하는 방법 역시 변한다. 그렇기에 개발자는 프로덕트가 지속적으로 유저에게 적절한 가치를 제공할 수 있도록 프로덕트를 가꾸어나가면서 복잡성을 조절해야만 한다.

이전의 프로젝트들에서는 이를 고려하지 못했기에 종료 이후 리팩토링하는 과정에서 어려움을 겪었다.

 

이를 위해 이번 프로젝트에서는 크게 두 가지 관점에서 개선하고자 했는데, 첫 번째가 바로 테스트 코드다.

테스트 도입 이유

확신을 가지고 코딩하기

테스트가 없는 경우와 테스트가 있는 경우를 비교해보자.

  • 초반
    • 테스트를 작성하지 않는다면, 빠르게 개발이 가능할 것이다. 테스트 작성 시간이 절약되니까!
    • 테스트를 작성한다면, 당신은 기능에 따라 어떤 테스트를 작성해야하는지 시간을 써야 할 것이다.
  • 중반
    • 테스트를 작성하지 않았다면, 당신은 구현한 기능이 정상적으로 작동하는지에 대해서 의구심이 생길 수 있다.
    • 테스트를 작성했다면, 테스트 결과를 확인하면서 개발하면 된다.
  • 후반, 그리고 앞으로도 계속
    • 테스트를 작성하지 않았다면, 다음의 경우로 인해 불안할 수 있다.
      1. 이 기능이 정상적으로 작동할까?
      2. 이 기능의 일부 로직을 수정해도, 기능이 정상적으로 작동할까?
      3. 이 기능의 일부 로직을 수정하면, 다른 기능에서 버그가 발생하지 않을까?
    • 테스트를 작성했다면, 확신을 가지고 계속 개발하면 된다.

위의 예시는 구현 및 수정만 예시로 든 것이고, 팀 단위 프로젝트라면 아래의 요인으로 인해 훨씬 더 큰 차이가 생겨날 수 있다.

  • 버그 발생 시 원인을 찾아낼 때
  • 문서화의 역할
  • 코드 리뷰 시간 단축
  • QA 입장에서도 어느정도 안정감을 가질 수 있음
  • 등등...

출처 - 단위 테스트 (책)

표로 나타낸다면, 이렇게 되지 않을까? 테스트가 없다면 프로젝트 초기에는 빠른 개발이 가능하지만, 시간이 지날수록 따라잡히기 마련이다. 

소프트웨어 엔트로피

이런 현상과 관계있는 단어가 소프트웨어 엔트로피다. 코드에서 무언가를 변경할 때마다 코드의 무질서도는 증가하며, 이를 지속적으로 정리하고 리팩토링해야만 한다.

만약 그러지 않는다면, 버그를 수정할 때 마다 도미노 현상처럼 더 많은 버그가 발생해 결국은 코드를 믿을 수 없게 된다. 또한 한 번 지저분해진 코드를 다시 깔끔하게 정리하기는 쉽지 않다. 깨진 유리창 이론처럼 사람들은 깔끔한 코드에는 깔끔한 코드를 추가하고, 지저분한 코드에는 지저분한 코드를 추가하기 마련이다.

 

실제로 삼성청년SW아카데미에서 프로젝트를 진행할 때, 타이트한 일정으로 인해 많은 지저분한 코드를 작성했다. 나중에 리팩토링을 진행하고자 했지만, 해당 코드들을 수정하면서 계속 '이 기능이 정상적으로 작동할까?' 혹은 '이 로직을 수정했다가 다른 기능에서 버그가 발생하지 않을까?'라는 걱정을 가지게 되었다.

요약

정리해보자면, 테스트 코드는 다음과 같은 장점이 있다.

  1. 테스트 코드가 정상적인 동작을 보장하기에, 확신을 가지고 코딩을 할 수 있다.
  2. 리팩토링 시에도 마찬가지로 적극적인 코딩이 가능하다.
  3. 빠르게 버그가 발견 가능하다.
  4. 문서화의 역할도 한다.

하지만 단점도 존재하긴 한다.

  1. 어쨌든, 초반에는 비용이 들어간다.
  2. 만약 나쁜 테스트 코드를 만든다면 득은 없고 유지 보수 비용만 상승한다.

3. 작성 방법

이 정도면 테스트의 중요함을 충분히 이해했을 것 같다. 이제 어떻게 테스트를 작성했는지 설명하겠다.

DAMP

DAMP는 'Descriptive and Meaningful Phrases'의 약자로 의미있고 설명적으로 문장을 작성하라는 원칙이다. 보통 개발자들은 중복된 코드를 작성하는 것을 지양하기 마련이다. 하지만 테스트 코드는 서로 독립적이고 격리되어야 올바르게 테스트가 진행될 수 있다. 그렇기에 중복을 줄이는 것을 지향하는 대신 의미를 파악하기 쉽도록 작성되어야 한다.

BDD 방법론

BDD란?

BDD는 테스트(test), 문서(documentation), 예시(example)를 한데 모아놓은 개념입니다.
- 모던 JavaScript 튜토리얼

작성 방법

BDD는 Given(주어진 환경), When(행위), Then(기대 결과)로 이루어져 있다.

  • Given: 테스트를 위해 설정하는 주어진 환경
  • When: 테스트의 목표 행위를 실행
  • Then: 기대 결과가 의도한대로 동작하는지 검증

코드 예시

describe('Follow 기능 테스트', () => {
  describe('none 상태일 때', () => {
    it('공개 계정이라면 following 상태로 변경된다.', async () => {
      //given
      //when
      //then
      });
    });

    it('비공개 계정이라면 pending 상태로 변경된다.', async () => {
      //given
      //when
      //then
      });
    });
  });
});

4. 래퍼런스