안드로이드 개발에서 테스팅은 애플리케이션의 품질을 보장하는 중요한 단계입니다. 특히 JUnit은 자바와 코틀린 환경에서 가장 널리 사용되는 테스팅 프레임워크이지만, JUnit4와 JUnit5 사이에는 상당한 차이가 있으며 이는 안드로이드 테스트 환경에서 여러 문제를 일으킬 수 있습니다. 이 글에서는 JUnit4와 JUnit5의 주요 차이점, Robolectric이 JUnit4만 지원하는 제약을 해결하는 방법에 대해 알아보겠습니다.
JUnit4 vs JUnit5
JUnit5
는 2017년 9월 10일에 처음 릴리즈 되었습니다. JUnit4
보다 여러 면에서 개선되었는데,가장 큰 차이점들을 살펴보겠습니다.
1. 아키텍처 차이
JUnit4:
- 단일
jar
파일로 제공 - 모놀리식 아키텍처
JUnit5:
-
모듈화된 구조
JUnit Platform
: 테스트 실행을 위한 기반JUnit Jupiter
: 새로운 테스트 APIJUnit Vintage
: JUnit3, JUnit4 호환성 지원
2. 어노테이션 변경
JUnit4 | JUnit5 | 설명 |
---|---|---|
@Before |
@BeforeEach |
각 테스트 메서드 전에 실행 |
@After |
@AfterEach |
각 테스트 메서드 후에 실행 |
@BeforeClass |
@BeforeAll |
클래스의 모든 테스트 전에 실행 |
@AfterClass |
@AfterAll |
클래스의 모든 테스트 후에 실행 |
@Ignore |
@Disabled |
테스트 비활성화 |
N/A | @DisplayName |
테스트에 사용자 정의 이름 부여 |
3. 새로운 기능들
JUnit5에서 추가된 주요 기능들:
- 중첩 테스트:
@Nested
어노테이션 - 태그 필터링:
@Tag
어노테이션 - 파라미터화된 테스트 개선:
@ParameterizedTest
,@ValueSource
,@CsvSource
등 - 확장 모델:
@ExtendWith
사용 - 조건부 테스트 실행:
@EnabledOnOs
,@EnabledIfSystemProperty
등 - 인터페이스 기본 메서드로 테스트 선언 지원
// JUnit4 예시
@Test
@Category(SlowTests.class)
public void myTest() {
// 테스트 코드
}
// JUnit5 예시
@Test
@Tag("slow")
@DisplayName("샘플 테스트")
void myTest() {
// 테스트 코드
}
안드로이드에서의 JUnit4와 JUnit5
안드로이드 테스트 환경은 주로 JUnit4
를 기반으로 구축되어 있습니다. 실제로 많은 사용해보셨을만한 아래의 안드로이드 테스팅 라이브러리들이 여전히 JUnit4
기반으로 동작합니다.
이러한 라이브러리들은 대부분 JUnit4의 @RunWith
, @Rule
등을 기반으로 작동합니다.
최근에 회사에서 스크린샷 통합 테스트 구축 작업을 진행하다가, 기존의 테스트 코드들이 Junit5
기반으로 동작하고 있어서 JVM UI 테스트를 위해 Robolectric을 셋업하는 과정에서 여러 이슈가 있었습니다.
Robolectric
간단하게 설명하자면, Robolectric은 안드로이드 UI 테스트를 JVM 에서 실행할 수 있게 해주는 강력한 도구입니다. 그러나 아쉽게도 Robolectric
은 현재까지도 JUnit4
기반에서만 동작합니다.
참고로, 이와 관련한 오픈 이슈도 있습니다.
Robolectric
의 핵심 기능은 JUnit4의 @RunWith
어노테이션을 사용하여 작동하고 있고, 아래의 예시처럼 사용할 수 있습니다.
// Robolectric 테스트 예시
@RunWith(RobolectricTestRunner::class)
class MyRobolectricTest {
@Test
fun testButton_click() {
val activity = Robolectric.setupActivity(MyActivity::class.java)
val button = activity.findViewById<Button>(R.id.my_button)
button.performClick()
// 검증 로직
}
}
JUnit5를 안드로이드에 적용하기
Gradle 테스트를 위해 JUnit5
를 사용하려면 useJUnitPlatform()
구성이 필요합니다.
// build.gradle.kts
tasks.withType<Test> {
useJUnitPlatform()
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.3")
}
그렇다면 JUnit5
와 Robolectric
을 함께 사용하려면 어떻게 해야할까요?
앞서 설명했던 JUnit Vintage
를 사용하시면 됩니다.
JUnit Vintage
는 JUnit3와 JUnit4 기반의 테스트를 위해 테스트 엔진을 제공해줍니다.
// build.gradle.kts
dependencies {
testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.9.3")
}
이 방법으로 JUnit4 + Robolectric 테스트
를 JUnit5
환경에서 실행할 수 있게 되었습니다.
결론
안드로이드 개발 생태계에서는 당분간 JUnit4, JUnit5 두 버전이 공존할 것으로 보입니다. Robolectric
과 같은 중요한 도구들이 여전히 JUnit4에 의존하고 있기 때문에, 점진적 전환 접근 방식이 현실적일 것 같습니다.
- 새로운 단위 테스트에 JUnit5 사용하기
- UI 및 통합 테스트에는 JUnit4 + Robolectric 유지하기
- JUnit Vintage를 통해 두 환경 통합하기
- (중요) 커뮤니티의 진행 상황을 주시하며 점차적으로 전환 계획 세우기
참고
- https://junit.org/junit5/docs/5.1.0/release-notes/index.html#release-notes-5.0.0
- https://github.com/robolectric/robolectric/issues/3477
- https://junit.org/junit5/docs/current/user-guide/
- https://github.com/android/android-test/issues/409
- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api
- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine
- https://mvnrepository.com/artifact/org.junit.vintage/junit-vintage-engine