TDD (Test-Driven-Development)

요즘 TDD 라는 용어로 테스트 주도 개발이라는 형태로 백엔드 프론트엔드 가릴 곳 없이 많이 개발하고 있습니다. 테스트 주도 개발이라는게 무엇이기에 많은 사람들이 선호 할까요?

  • TDD는 코드 작성전에 테스트를 작성하고 테스트에 통과하도록 코드를 작성하는 것 입니다.

  • 테스트 코드를 활용하는 형태로 red-green test 라고 불리우는데 코드 작성전에 테스트에 실패하는 레드 테스트를 먼저 실행하고 코드 작성후에는 통과하는 테스트로 그린 테스트를 작성하는 것 입니다.

  • 그래서 테스트를 하기 전에 약간의 코드를 작성해서 테스트에 오류가 발생하지 않도록 합니다. (함수를 작성하거나, 컴포넌트를 작성하므로서 말 입니다.)
    하지만 이때에는 아무것도 하지않는 빈 함수를 작성합니다.

  • 이후 테스트코드를 작성하고 테스트를 진행하면 함수나 컴포넌트는 아무런 기능이 없는 상태이기 때문에 테스트에 실패합니다. 그다음 함수나 컴포넌트의 기능을 완성해서 테스트에 통과하도록 합니다.

왜 TDD를 사용해서 개발할까요?

  • 테스트를 작성하는 것이 프로세스의 한 부분으로 느끼는 방식에 차이가 있기 때문입니다. 테스트를 작성하는 것은 코드를 작성하는 하나의 단계이자 프로세스 입니다. 그래서 테스트 코드를 작성하는 것이 번거롭지 않게 느껴집니다.

  • 효율적 입니다. 코드를 작성하면서 원하는 대로 작동되는지 확인하면서 소프트웨어를 업데이트 할 텐데 이는 수동적으로 개발자가 눈으로 확인 하는 테스트입니다. 하지만 코드 작성전에 테스트를 작성한다면 코드변경 후에 자동으로 테스트를 실행할 수 있습니다.

  • 개발하면서 모든 테스트케이스를 작성해두면 변경사항이 생길때 마다 모든 테스트를 다시 실행해서 자동으로 테스트를 할 수 있습니다. 이러한 방식은 매번 애플리케이션을 실행시켜서 눈으로 해당사항을 확인할 필요가 없습니다.

이러한 이유로 테스트 주도 개발인 TDD를 선호하는 추세 입니다.

물론 개발 속도가 줄어든다는 단점이 있지만 점점 프로젝트가 커지게 된다면 어떤 코드가 안정한지, 버그가 발생하는 지점이 어디인지 찾는 디버깅에 있어서 엄청나게 효율적인 방식을 보여줍니다.

React Test Library의 철학

RTL은 React 테스트에 대해서 모범적인 사례를 지향합니다.

  • RTL은 테스트를 위한 가상 DOM을 생성하고 DOM과 상호작용하기 위한 유틸리티를 제공합니다.
  • 이를 통해서 브라우저를 통하지 않고도 테스트를 가능하게 해줍니다.

Unit Test (유닛 테스트)

  • 보통 함수나 별개의 컴포넌트를 코드의 한 유닛으로서 잡고 이를 테스트 하는 것 입니다.
  • 유닛 테스트는 테스트 대상을 하나의 유닛으로 취급함으로서 독립적인 기능에 대해서 테스트를 하는 것일 뿐 다른 코드의 유닛과 상호작용하는 것을 테스트 하지 않습니다.

Integration Test (통합 테스트)

  • 여러 유닛이 함께 작동하는 방식을 테스트 함으로서 유닛간의 상호작용을 테스트 하는 겁니다.

Funtional Test (기능 테스트)

  • 기능 테스트는 소프트웨어의 특정기능을 테스트 하는 것 입니다. 다양한 통합테스트가 모여서 하나의 기능을 테스트 할 수도 있지만 하나의 유닛테스트가 하나의 기능테스트가 될수도 있습니다,

  • 기능 테스트의 목적은 코드의 테스트가 아닌 동작의 테스트를 의미 합니다. 즉, 입력칸에 잘못된 데이터를 입력하면 빨간 박스가 뜨는지 테스트 하는 것등이 됩니다.

  • RTL은 코드의 테스트가 아니라 사용자 시나리오 테스트를 권장합니다. 즉 기능테스틀 권장하고 있습니다.

End To End Test (인수 테스트 | E2E 테스트)

  • 이 테스트는 실제로 애플리케이션이 동작하는 환경이 필요합니다. (Cypress 혹은 Selenium) 과 같은 특별한 도구들이 필요합니다. 하지만 수동으로 애플리케이션을 실행하면서 눌러보는 것도 이 테스트에 속합니다.

유닛 테스트와 기능 테스트

유닛 테스트의 방식

  • 유닛 테스트는 테스트를 다른 케이스로 부터 최대한 격리 시킵니다. 따라서 함수나 컴포넌트를 테스트 할때 의존성을 표시합니다.
  • 함수나 컴포넌트가 실행할때 다른 함수나 컴포넌트에 의존성을 가지게 된다면 해당 함수나 컴포넌트를 실제버전 대신 테스트 버전을 사용합니다. 따라서 어떤 문제가 발생하거나 테스트가 실패하게 되면 의존하게 되는 함수나 컴포넌트가 아니라 테스트를 진행한 유닛이 문제가 되는 것입니다.

    - 이는 매우 정확하고 쉽게 테스트의 실패원인을 찾을 수 있게 합니다.

단점 :
1. 이는 사용자가 소프트웨어를 사용하는 방식과 다릅니다. 즉, 사용자가 소프트웨어를 사용하는 방식이 달라서 유닛테스트를 통과하는 경우에도 버그가 있을 수 있습니다. 혹은 사용자는 소프트웨어를 정상적으로 사용함에도 유닛테스트가 통과하지 않을 수도 있습니다.

  1. 리팩토링으로 인해 유닛 테스트가 실패하게 될 수도 있습니다. 리팩토링은 동작을 변경하지 않고 소프트 웨어 작성방식을 변경하는 것으로 유닛테스트로 소프트웨어가 어떻게 작성되었는지 테스트를 하는데 이 방식이 바뀌었기 때문에 유닛테스트 케이스가 실패할 수 있습니다.

기능 테스트의 방식

  • 기능 테스트는 테스트 하는 특정 동작이나 유저플로우와 연관된 유닛을 포함합니다. 이는 사용자가 어플리케이션을 사용하는 방식과 흐름이 유사하여 테스트를 통과하면 사용자는 기능을 사용하는데 문제가 없고 실패하면 사용자가 기능을 사용하는데 문제가 있을 확률이 높습니다.

  • 코드를 리팩토링해도 기능자체가 유효하다면 테스트도 통과하게 됩니다.

단점 :
1. 하지만 만약 기능 테스트를 실패하게 된다면 어떤 부분에서 문제가 있는지 디버깅하기가 어려워 집니다. 코드가 테스트와 유닛테스트 처럼 밀접하게 연결되어있지 않아서 어떤 부분의 코드가 문제가 있는지 잘 알 수가 없습니다.

TDD vs BDD (Behavior-Driven-Development)

  • RTL은 기능테스트를 권장하고 있는데 결국이는 사용자의 행동을 테스트 하는 방식을 권장하고 있습니다.
    하지만 이는 BDD는 아닙니다.
  • BDD는 다양한 역할간의 협업이 필요합니다. QA, 개발자, 사업 파트너등이 상호 작용하는 방식에 대한 프로세스도 정의 되어있습니다. 따라서 개발자는 TDD로서 사용자의 행동에 대해서 테스트를 하는 형태로 개발을 진행합니다.
profile
일상을 기록하는 삶을 사는 개발자 ✒️ #front_end 💻

0개의 댓글