- 학습 목표: 안드로이드에서 비즈니스 로직을 검증하는 단위 테스트 작성법 학습
- 학습 항목:
- JUnit 기본 개념 및 구조
- 안드로이드에서 JUnit 4와 JUnit 5 사용법
- Mocking과 Stubbing: Mockito 활용
- 예외 상황 처리 테스트
1. JUnit 기본 개념 및 구조
JUnit은 자바 기반의 테스트 프레임워크로, 안드로이드에서는 주로 비즈니스 로직의 단위 테스트에 사용됩니다.
1.1. JUnit의 기본 주기
- 설정(Setup): 테스트 전에 초기화 작업을 수행합니다. 일반적으로 @Before 어노테이션을 사용하여 테스트 환경을 설정합니다.
- 테스트 실행(Test): 테스트가 진행됩니다. 각각의 테스트 메서드는 @Test 어노테이션으로 정의됩니다.
- 정리(Teardown): 테스트가 완료된 후, 자원을 해제하거나 정리하는 작업을 수행합니다. @After 어노테이션을 사용하여 정리 작업을 합니다.
1.2. 기본 JUnit 어노테이션
- @Test: 테스트 메서드를 정의합니다.
- @Before: 각 테스트 메서드가 실행되기 전에 수행할 작업을 지정합니다.
- @After: 각 테스트 메서드가 끝난 후 수행할 작업을 지정합니다.
- @BeforeClass, @AfterClass: 클래스의 모든 테스트 메서드 전에/후에 한 번만 실행됩니다.
1.3. JUnit의 주요 기능
- assert: 테스트에서 기대하는 결과를 확인하기 위해 사용합니다.
- assertEquals(expected, actual): 두 값이 같은지 비교.
- assertTrue(condition): 조건이 참인지 확인.
- assertFalse(condition): 조건이 거짓인지 확인.
- assertNull(object): 객체가 null인지 확인.
- assertNotNull(object): 객체가 null이 아닌지 확인.
- assertThrows(expectedException.class, executable): 예외가 발생하는지 확인.
import org.junit.Assert.*
import org.junit.Before
import org.junit.Test
class CalculatorTest {
lateinit var calculator: Calculator
@Before
fun setUp() {
calculator = Calculator()
}
@Test
fun testAddition() {
val result = calculator.add(2, 3)
assertEquals(5, result)
}
@Test(expected = IllegalArgumentException::class)
fun testDivision_byZero_throwsException() {
calculator.divide(10, 0)
}
}
위 코드에서 @Before 어노테이션은 각 테스트 전에 호출되며, @Test는 실제 테스트 메서드를 나타냅니다. assertEquals는 두 값이 같은지 테스트합니다.
2. 안드로이드에서 JUnit 4와 JUnit 5 사용법
안드로이드에서는 JUnit 4와 JUnit 5 모두를 사용할 수 있습니다. 기본적으로 안드로이드 프로젝트에서 JUnit 4가 기본으로 설정되어 있지만, JUnit 5를 사용할 수도 있습니다.
2.1. JUnit 4 사용
기본적으로 안드로이드 프로젝트에 포함된 testImplementation 'junit:junit:4.13.2'을 통해 사용할 수 있습니다.
2.2. JUnit 5 사용
JUnit 5는 더 많은 기능을 제공하며, 특히 다중 플랫폼 테스트에서 강력한 도구입니다. 사용하려면 Gradle에 다음 의존성을 추가해야 합니다:
testImplementation "org.junit.jupiter:junit-jupiter-api:5.7.0"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.7.0"
3. Mocking과 Stubbing: Mockito 활용
Mockito는 외부 의존성을 가진 객체의 동작을 모킹(mocking)하여 테스트할 수 있도록 해주는 프레임워크입니다. 이 프레임워크를 이용하면 실제 객체 대신 테스트에서 사용할 가짜 객체를 생성할 수 있습니다.
3.1. Mockito 기본 사용법
- mock(): 객체를 모킹합니다.
- when(…).thenReturn(…): 특정 메서드가 호출되었을 때 예상되는 결과를 지정합니다.
- verify(): 메서드 호출 여부를 확인합니다.
import org.junit.Test
import org.mockito.Mockito.*
class UserServiceTest {
val mockRepository = mock(UserRepository::class.java)
val userService = UserService(mockRepository)
@Test
fun testGetUser_returnsCorrectUser() {
val expectedUser = User("John", 25)
`when`(mockRepository.getUser(1)).thenReturn(expectedUser)
val result = userService.getUser(1)
assertEquals(expectedUser, result)
verify(mockRepository).getUser(1)
}
}
위 예제에서 mock(UserRepository::class.java)를 사용하여 UserRepository 객체를 모킹하고, when(…).thenReturn(…)으로 예상 결과를 설정한 후, 그 결과를 검증합니다.
3.2. Stubbing
Stubbing은 테스트 중인 코드의 행동을 미리 정의하는 것입니다. 특정 조건에서 호출될 때 특정 행동을 하도록 객체를 설정할 수 있습니다.
4. 예외 상황 처리 테스트
테스트에서는 다양한 예외 상황에 대한 테스트도 필요합니다. JUnit에서 제공하는 @Test(expected = Exception.class)를 사용하거나, JUnit 5에서 assertThrows() 메서드를 사용할 수 있습니다.
@Test(expected = IllegalArgumentException::class)
fun testDivideByZero_throwsException() {
calculator.divide(10, 0)
}
또는 JUnit 5에서는 다음과 같이 처리할 수 있습니다.
@Test
fun testDivideByZero_throwsException() {
assertThrows<IllegalArgumentException> {
calculator.divide(10, 0)
}
}
5. 의존성 주입된 클래스 테스트
의존성 주입된 클래스의 단위 테스트는 Mocking 기법을 사용하여 외부 의존성을 대체하고 테스트하는 방식으로 수행됩니다. 안드로이드에서는 Hilt 또는 Dagger와 같은 DI(Dependency Injection) 라이브러리를 자주 사용하므로, 이러한 도구들과 결합된 테스트 방법을 이해하는 것이 중요합니다.
@HiltAndroidTest
class ExampleTest {
@Inject
lateinit var repository: ExampleRepository
@Before
fun setUp() {
hiltRule.inject()
}
@Test
fun testExampleFunction() {
val result = repository.exampleFunction()
assertEquals(expectedResult, result)
}
}
'안드로이드 > 테스트' 카테고리의 다른 글
안드로이드 TDD, 안정된 개발 환경 구축 (0) | 2024.11.04 |
---|---|
[안드로이드 / Test] 3. Android Instrumentation Test (통합 테스트) (0) | 2024.10.31 |
[안드로이드 / Test] 1. 테스트 개념 이해 및 중요성 (0) | 2024.10.24 |
안드로이드 앱 개발 시 테스트에 대해 학습할 수 있는 커리큘럼 (0) | 2024.10.24 |