- 소프트웨어 개발에서 개별적인 코드 단위를 테스트하는 것을 의미합니다. - 코드의 작은 부분을 격리시켜 독립적으로 테스트함으로써 코드의 정확성과 신뢰성을 검증합니다. - 자동화가 되고 반복 가능하며 버그를 빠르게 찾아내고 수정하는데 도움이 됩니다. 또한 코드 변경 시 기존 기능에 영향을 주지 않고 코드의 동작을 확인하는 데 유용합니다. 💡 단위 테스트의 범위
- 클래스, 메서드, 함수와 같은 작은 단위의 코드를 격리시켜 독립적으로 테스트하는 것을 의미합니다. - 따라서, 컨트롤러단이나 서비스단과 같은 구성 요소는 각각 개별적인 단위로 테스트될 수 있습니다.
2) JUnit5 구성요소
💡 jUnit5 구성요소
- JUnit5에서는 Platform, TestEngine Interface, TestEngine, Jupiter, Vintage으로 구성이 되어 있습니다.
- JUnit 테스트를 실행하는데 사용되는 실행환경입니다. - 이는 다양한 TestEngine 구현체를 실행하고 테스트 결과를 보고하는 역할을 수행합니다.
TestEngine Interface
- JUnit Platform에서 테스트 엔진을 정의하는 데 사용됩니다. - 이 인터페이스를 구현하여 사용자 정의 테스트 엔진을 만들 수 있습니다.
TestEngine
- JUnit Platform에서 테스트를 실행하는 데 사용되는 구현체입니다. - 각각의 TestEngine은 특정한 테스트 프레임워크 또는 런처와 통합되어 동작하며, 테스트 수명주기 관리, 테스트 실행, 결과 보고 등의 기능을 제공합니다.
JUnit Jupiter
- JUnit 5에서 제공되는 새로운 프레임워크입니다. - 이는 테스트 작성과 실행을 위한 새로운 기능과 어노테이션을 제공하며, JUnit 4보다 더 강력하고 유연한 테스트 코드 작성이 가능합니다.
JUnit Vintage
- JUnit 4와의 하위 호환성을 제공하기 위한 모듈입니다. - 이 모듈은 JUnit 4로 작성된 테스트를 JUnit 5 플랫폼에서 실행할 수 있게 해줍니다.
1. JUnit Platform
💡 JUnit Platform
- JUnit 테스트를 실행하는 데 사용되는 실행 환경을 의미합니다. TestEngine Interface를 통하여 다른 TestEngine 구현체들과 상호작용하여 테스트를 실행하고 테스트 결과를 보고하는 역할을 수행하는 테스트 프레임워크입니다.
- 테스트의 수행 과정은 발견, 실행, 결과 보고의 과정을 통해서 수행이 됩니다.
💡 JUnit Platform의 주요 특징 1. JUnit Platform에서 TestEngine Interface를 통해 테스트 엔진(Jupiter, Vintage)과 상호작용을 합니다. - 테스트 엔진과의 통신을 통해 테스트 수명주기 관리, 동적 테스트 검색 및 실행, 테스트 결과 보고 등을 지원합니다.
2. JUnit 3, 4, 5와 같은 테스트 프레임워크를 지원합니다. - JUnit 5와의 호환성을 제공하며, JUnit 4로 작성된 테스트를 JUnit 5 플랫폼에서도 실행할 수 있도록 하는 모듈을 포함하고 있습니다.
3. 다양한 환경 및 설정에서 테스트를 실행할 수 있습니다. - 테스트 실행을 위한 표준화된 인터페이스를 제공하여 다양한 테스트 프레임워크와 런처가 통합될 수 있도록 합니다. 이를 통해 개발자는 자신이 선호하는 테스트 프레임워크를 사용하여 테스트를 작성하고, JUnit Platform에서 실행할 수 있습니다.
[ 더 알아보기 ] 💡Test Framework와 TestEngine의 차이는?
- 테스트 프레임워크는 테스트를 작성하고 실행하기 위한 구조와 규칙을 제공하며 TestEngine은 테스트를 실행하는 엔진으로 테스트를 ‘실제 실행하고 결과를 반환하는 역할’을 담당합니다.
2. TestEngine Interface
💡 TestEngine Interface - JUnit Platform에서 테스트를 실행하고 결과를 보고하는 데 사용이 되는 인터페이스로 TestEngine에 대한 메서드와 속성을 정의하는 데 사용이 됩니다.
- TestEngine Interface를 기반으로 TestEngine의 구현체를 구성합니다. 이를 통해 사용자 정의 TestEngine을 만들 수 있습니다.
💡 [참고] TestEngine Interface의 주요 메서드
메서드
리턴 타입
설명
discover()
void
- 테스트를 발견하고 고유한 ID를 부여하는 메서드입니다.
execute()
void
- 테스트를 실행하는 메서드입니다.
getId()
String
- 테스트 엔진의 고유 식별자를 반환하는 메서드입니다.
getGroupId()
String
- 테스트 엔진의 그룹 식별자를 반환하는 메서드입니다.
getVersion()
String
- 테스트 엔진의 버전을 반환하는 메서드입니다.
3. TestEngine
💡 TestEngine - TestEngine Interface의 구현체로 테스트를 실행하는 데 사용이 됩니다.
- 각각 TestEngine은 특정한 테스트 프레임워크 또는 런처와 통합되어 동작하며, 테스트 수명주기 관리, 테스트 실행, 결과 보고 등의 기능을 제공합니다.
4. JUnit Jupiter
💡 JUnit Jupiter
- JUnit 5에서 제공되는 새로운 프레임워크를 의미하며 테스트 작성과 실행을 위한 기능을 어노테이션을 제공하며 JUnit4 보다 강력하고 유연한 테스트 코드를 작성하도록 제공해 줍니다.
💡 [참고] JUnit Jupiter의 주요 어노테이션
- 3) 주요 어노테이션 & 메서드 부분에서 상세하게 알아봅니다.
어노테이션
설명
@Test
테스트 메서드를 정의하는 데 사용되는 어노테이션입니다. 이 어노테이션이 지정된 메서드는 JUnit Jupiter에서 테스트로 실행됩니다.
@ParameterizedTest
매개변수화된 테스트를 정의하는 데 사용되는 어노테이션입니다. 이 어노테이션이 지정된 메서드는 여러 매개변수를 사용하여 반복적으로 실행됩니다.
@BeforeEach
각각의 테스트 메서드가 실행되기 전에 실행되는 코드를 정의하는 데 사용되는 어노테이션입니다.
@AfterEach
각각의 테스트 메서드가 실행된 후에 실행되는 코드를 정의하는 데 사용되는 어노테이션입니다.
5. JUnit Vintage
💡 JUnit Vintage - JUnit 3, 4의 TestEngine을 JUnit 5 플랫폼에서 사용할 수 있도록 제공을 합니다.
- JUnit 5 플랫폼을 사용하여 JUnit 4 테스트를 실행할 수 있으며, JUnit 5의 다양한 기능과 호환성을 유지할 수 있습니다. 또한 기존의 테스트 코드를 유지하면서도 JUnit 5의 새로운 기능과 개선점을 활용할 수 있습니다.
6. 구성 요소 별 전반적인 흐름
💡 구성 요소 별 전반적인 흐름
1. 사용자는 IDE Tool을 이용하여 테스트 코드를 실행합니다.
2. 테스트 코드는 JUnit Platform 내에서 수행이 됩니다.
3. 테스트 코드를 구성하는 메서드나 어노테이션에 대해서는 TestEngine Interface를 이용하여 호출하여 구성합니다.
4. TestEngine Interface의 실제 구현되는 구현체는 Junit Jupiter, Junit Vintage, Custom Engine을 기반으로 구현이 됩니다.
3) JUnit 5 주요 어노테이션 & 메서드
1. JUnit 5 어노테이션
💡JUnit 5 어노테이션 - JUnit Jupiter에서는 테스트 구성 및 프레임워크 확장을 위해 다음 어노테이션들을 지원합니다.
- '메소드명_테스트대상상태_예상동작' 형식으로 JUnit 메서드 명을 지정하는 방식입니다.
- 이 전략에 대해서는 메소드 이름이 코드 리팩토링의 일부로 변경된다면 이 테스트 이름도 변경되어 나중에 이해하기 어려워진다는 반대 의견이 있습니다.
[ 사용 예시 ]
- isAdult_AgeLessThan18_False : 만약 나이가 18보다 작으면 성인이 아님 (False)을 반환하는 경우 - withdrawMoney_InvalidAccount_ExceptionThrown : 잘못된 계정으로 출금 시 예외가 발생하는 경우 - admitStudent_MissingMandatoryFields_FailToAdmit: 필수 입력 필드가 누락되었을 때 학생을 입학시키지 못하는 경우
4.2. 명명 규칙 -2 : '메서드명_예상동작_테스트대상상태 '형식
💡 MethodName_ExpectedBehavior_StateUnderTest - “메서드명_예상동작_테스트대상상태” 형식으로 JUnit 메서드 명을 지정하는 방식입니다.
- 조금 다른 방식으로 변경된 것이지만, 일부 개발자들은 이 명명 기법을 사용하는 것을 권장합니다. 이 기법은 메서드 이름이 변경되면 이해하기 어려워진다는 단점도 있습니다.
[사용 예시]
- isAdult_False_AgeLessThan18: 만약 나이가 18보다 작으면 성인이 아님 (False)을 반환하는 경우 - withdrawMoney_ThrowsException_IfAccountIsInvalid: 잘못된 계정으로 출금 시 예외가 발생하는 경우 - admitStudent_FailToAdmit_IfMandatoryFieldsAreMissing: 필수 입력 필드가 누락되었을 때 학생을 입학시키지 못하는 경우
4.3. 명명 규칙 -3: “test” 접두어 형식
💡 test [Feature being tested]
- “test” 접두어 형식으로 JUnit 메서드 명을 지정하는 방식입니다.
- "test" 접두어가 중복된다는 주장도 있지만, 일부 개발자들은 이 기법을 사용하는 것을 선호합니다. 또한 SonarLint에 code smells를 피할 수 있다는 이유로 권장됩니다.
[사용 예시]
- testIsNotAnAdultIfAgeLessThan18: 만약 나이가 18보다 작으면 성인이 아님을 테스트합니다. - testFailToWithdrawMoneyIfAccountIsInvalid: 잘못된 계정으로 출금 시 실패하는 것을 테스트합니다. - testStudentIsNotAdmittedIfMandatoryFieldsAreMissing: 필수 입력 필드가 누락되었을 때 학생이 입학되지 않는 것을 테스트합니다.
4.4. 명명 규칙-4 : 테스트할 기능 형식
💡 Feature to be tested
- 일부는 메서드를 테스트 메서드로 식별하기 위해 이미 주석을 사용하고 있으므로, 단순히 테스트할 기능을 작성하는 것이 더 좋다고 제안합니다.
- 이는 단위 테스트를 문서의 대체 형태로 만들어주고 SonarLint에 code smells를 피할 수 있다는 이유로 권장됩니다.
4.5. 명명 규칙 -5: Should_예상동작_테스트대상상태 형식
💡 Should_ExpectedBehavior_When_StateUnderTest
- 'Should_예상동작_When_테스트대상상태'로 JUnit 메서드 명을 지정하는 방식입니다.
[사용예시]
- Should_ThrowException_When_AgeLessThan18: 만약 나이가 18보다 작으면 예외를 던져야 합니다. - Should_FailToWithdrawMoney_ForInvalidAccount: 잘못된 계정일 경우 출금에 실패해야 합니다. - Should_FailToAdmit_IfMandatoryFieldsAreMissing: 필수 입력 필드가 누락되었을 때 입학에 실패해야 합니다.
4.6. 명명 규칙 -6: When_테스트대상상태_Expect_예상동작 형식
💡 When_StateUnderTest_Expect_ExpectedBehavior
- 'When_테스트대상상태_Expect_예상동작'으로 JUnit 메서드 명을 지정하는 방식입니다.
[사용예시]
- When_AgeLessThan18_Expect_isAdultAsFalse: 만약 나이가 18보다 작으면 성인이 아님 (False)을 예상합니다. - When_InvalidAccount_Expect_WithdrawMoneyToFail: 잘못된 계정으로 출금 시 실패할 것을 예상합니다. - When_MandatoryFieldsAreMissing_Expect_StudentAdmissionToFail: 필수 입력 필드가 누락되었을 때 학생 입학이 실패할 것을 예상합니다.
- Behavior-Driven Development (BDD)의 일부로 개발된 명명 규칙입니다. 테스트를 사전 조건 (Given), 테스트 대상 상태 (When), 예상 동작 (Then)으로 세 가지 부분으로 나누어 작성합니다.
- 이 접근 방식은 Behavior-Driven Development (BDD)의 일부로 개발된 명명 규칙에 기반을 두고 있습니다. 개별 테스트를 세 부분으로 나눠 사전 조건, 테스트 대상 상태 및 예상 동작을 위의 형식에 맞춰 작성합니다. [사용예시] - Given_UserIsAuthenticated_When_InvalidAccountNumberIsUsedToWithdrawMoney_Then_TransactionsWillFail: 사용자가 인증된 상태에서 잘못된 계정 번호를 사용하여 금액을 인출하면 거래가 실패할 것입니다.