회원가입을 하면 원하는 문장을
저장할 수 있어요!
다음
AWS 이용 중이라면 최대 700만 원 지원받으세요
소프트웨어 개발에서 있어서 단위 테스트(Unit Testing)는 중요한 절차입니다. 소프트웨어의 각 유닛(Unit)을 테스트하고, 전반적인 프로젝트 생산성과 유지 보수에 영향을 미치기 때문이죠. 이와 관련하여 이번 글에서는 테스트 주도 개발과 단위 테스트에 대해 간단히 알아보고, 자바 프로젝트에서 사용되는 단위 테스트 도구인 JUnit의 사용 방법과 유용한 팁을 정리해보았습니다.
회원가입을 하면 원하는 문장을
저장할 수 있어요!
다음
회원가입을 하면
성장에 도움이 되는 콘텐츠를
스크랩할 수 있어요!
확인
소프트웨어 개발에서 있어서 단위 테스트(Unit Testing)는 중요한 절차입니다. 소프트웨어의 각 유닛(Unit)을 테스트하고, 전반적인 프로젝트 생산성과 유지 보수에 영향을 미치기 때문이죠. 이와 관련하여 이번 글에서는 테스트 주도 개발과 단위 테스트에 대해 간단히 알아보고, 자바 프로젝트에서 사용되는 단위 테스트 도구인 JUnit의 사용 방법과 유용한 팁을 정리해보았습니다.
테스트 주도 개발(Test-driven Development)이란, 테스트 케이스를 작성하고 소스 코드가 이를 통과하는지 반복 확인하며 프로젝트를 진행하는 것을 말합니다. 테스트 주도 개발은 소프트웨어 개발 방법론 중 하나로서 간단히 ‘TDD’라고도 하는데요. TDD는 기능의 구현 목표에 집중하여 개발 생산성을 높이고, 이후 발생할 리팩토링(Refactoring)을 지속할 수 있게 하는 근간이 되기도 합니다.
단위 테스트는 소프트웨어의 클래스(Class), 함수(Function) 등 각 단위가 구현 목표에 맞게 동작하는지를 확인하는 단계입니다. 자바 프로젝트에서는 주로 클래스를 기준으로 각 메소드(method)가 예상한 대로 정확히 동작하는지를 파악합니다.
제이유닛(JUnit)은 자바 프로젝트를 위한 단위 테스트 프레임워크(Unit Testing Framework)입니다. 테스트 코드를 작성하기 위해 필요한 다양한 API를 제공하며, 자동으로 테스트를 수행하고 결과를 출력해줍니다. JUnit은 1997년에 출시되어 오래된 역사를 가지고 있으며, 자바 프로젝트의 테스트 주도 개발에 있어서 핵심적인 역할을 하고 있습니다.
JUnit은 현재 버전 5까지 발표되었으며, 제이유닛 플랫폼(JUnit Platform), 주피터(JUnit Jupiter), 빈티지(JUnit Vintage) 등 3개의 모듈로 구성되어 있습니다. 이 중에서 JUnit Platform이 핵심 모듈이며, 인텔리제이(IntelliJ), 이클립스(Eclipse), 비주얼 스튜디오 코드(VS Code) 등 대표적인 IDE에 내장되어 있습니다. 그 외 JUnit Jupiter는 프로그래밍 모델과 확장 모델을, JUnit Vintage는 이전 버전의 JUnit을 지원하는 모듈입니다.
JUnit을 사용하려면 먼저 각 클래스 별로 테스트 클래스(Test Class)를 만들어야 합니다. 그다음 테스트 클래스 안에 테스트 메소드를 작성하고 @Test 애노테이션(Annotation)을 붙입니다. JUnit은 @Test Annotation이 붙은 메소드에 대해 자동으로 테스트를 실행하고 결과를 출력하게 됩니다.
위 코드는 소수(Prime Number)를 생성하는 함수와 짝수(Even Number) 여부를 판별하는 함수에 대한 간단한 테스트 케이스입니다. JUnit 테스트 케이스에서는assertEquals(), assertTure() 등 다양한 assert 메소드를 사용하여 함수 호출 시 기대 값(expected value)과 실제 값(actual value)을 비교하는 방식으로 테스트를 진행합니다.
테스트 케이스 명명 규칙(Test Case Conventions)은 일관성 있게 테스트 케이스를 작성하도록 만든 규칙을 의미합니다. 현재 다양한 규칙이 알려져 있으며, 각 프로젝트에 맞게 별도의 명 명규칙을 지정하여 사용합니다. 테스트 케이스 명명 규칙은 개발 생산성에 영향을 미치기 때문에 프로젝트 진행 시 미리 충분한 검토가 필요 부분이기도 합니다.
대표적으로 사용되는 테스트 케이스 명명 규칙으로는 여러 가지가 있지만 아래와 같이 크게 3가지 범주로 나눠볼 수 있습니다. (참고: 7 Popular Unit Test Naming Conventions)
첫 번째 명명 규칙은 method 이름을 기준으로 테스트 케이스를 작성하는 것입니다. 직관적으로 어떤 method를 테스트하는 것인지 알 수 있는 장점이 있지만, method 이름이 바뀌면 테스트 케이스명도 바뀌어야 하는 단점이 있습니다. (예시: isAdult_AgeLessThan18_False)
두 번째 명명 규칙은 테스트하고자 하는 기능을 기술하듯이 적는 방식입니다. 이 방식을 활용하면 method 변경에 구애받지 않고 리팩토링 작업을 할 수 있습니다. 다만, 영어가 부족하거나 개발 경험이 적으면 테스트 케이스 작성에 어려움을 느낄 수 있으며, 일관성이 떨어져 보일 수도 있습니다. (예시: IsNotAnAdultIfAgeLessThan18)
세 번째 명명 규칙은 Given, Should, When, Then 등의 단어를 활용하는 방식입니다. 이 규칙을 사용하면 일관성 있게 테스트 케이스를 작성할 수 있으며, method 이름 변경에 영향을 받지 않을 수 있습니다. 따라서 앞선 두 가지 방식의 단점을 어느 정도 보완한 방식이라고 할 수 있습니다. (예시: Should_ThrowException_When_AgeLessThan18)
앞서 대표적인 3가지 테스트 케이스 작성 규칙을 살펴보았는데요. 이 중에서 ‘어떤 방식이 무조건 좋다’라는 것은 없습니다. 따라서 테스트 케이스 명명 규칙은 전체적인 프로젝트 규모와 기간, 개발자의 테스트 케이스 작성 수준 등을 고려하여 선정해야 합니다.
테스트 주도 개발을 하다 보면 테스트 데이터를 만드는 데 많은 시간을 쓰게 됩니다. 특히 테스트 데이터를 수동으로 만들면 시간도 많이 걸리고 데이터가 편향성을 가질 수도 있습니다. 따라서 아래 그림과 같이 랜덤하게 문자열이나 숫자를 자동으로 생성하는 함수를 활용하면, 테스트 케이스 작성 시간을 절약할 수 있을 뿐만 아니라 데이터 편향성도 제거할 수 있습니다.
테스트 케이스를 작성하다 보면 여러 개의 assert 메소드를 사용하거나 assertAll을 넣는 경우가 있습니다. 이렇게 하면 테스트 실패 시 디버깅이 오래 걸릴 수 있으며, ‘단위 테스트 케이스는 단일 기능을 테스트해야 한다’는 원칙에도 부합하지 않게 됩니다. 따라서 만약 한 개의 테스트 케이스에 여러 개의 assertion을 넣고 싶다는 유혹이 든다면, 해당 테스트 케이스를 더 잘게 쪼갤 수는 없는지 다시 생각해 볼 필요가 있습니다.
이상 테스트 주도 개발과 단위 테스트에 대해 간단히 알아보고, 자바 테스트 도구인 JUnit의 사용 방법과 유용한 팁을 정리해 봤습니다. JUnit은 테스트 케이스를 작성하고 실행하는 것을 편리하게 해 준 도구입니다. 다만, 제대로 테스트 케이스를 작성하고 JUnit을 활용하려면 많은 시행착오와 경험을 쌓아야 하는데요. 추가로 JUnit 최신 버전에 대한 자세한 내용을 찾아보고 싶으면 Junit5 User Guide를 참고해 보길 바랍니다.
요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.