-
안드로이드 앱 테스트 기본 - 1 (JUnit Test 예제 포함)카테고리 없음 2024. 12. 4. 18:18
자바를 배우면서 JUnitTest를 사용해본 경험이 있다. 안드로이드에서도 앱 테스트 코드를 만들어서 테스트 한다는 것을 알고는 있었지만 학습해본 적이 없어서 이번에 한번 학습해보려고 한다.
1. 테스트 코드를 작성하는 이유 ?
일반적으로 내가 개발할때 테스트하는 것은 앱을 에뮬레이터나 스마트폰에 직접 설치 후 사용해보는 방식으로 테스트를 해봤다. 하지만 프로젝트의 규모가 크다면 앱을 build하는 시간도 오래 걸리고 ui를 만드는 시간도 걸리기 때문에 테스트 속도가 느려진다. 또한 반복적인 테스트를 해야하는 상황이라면 앱을 일일이 빌드하고 테스트 해보는 것은 비효율적일 수 있다.
이러한 부분에서 장기적으로 봤을때는 테스트 코드를 만들어 놓은다면 똑같은 테스트를 해야하는 경우는 시간을 절약할 수 있고 빌드하는 시간들 ui 구성하는 시간 등등을 절약하며 테스트 할 수 있다. (장점)
물론 만능은 아니다. 테스트 코드를 작성하는 것 자체에 시간이 들기 때문에 작은 프로젝트에서는 굳이 해야할 필요가 없다. 그리고 프로젝트가 수정되는 것에 따라서 테스트 코드 또한 수정되야 하는 등의 단점이 있다.
그래서 프로젝트의 상황에 맞게 도입하는 것이 중요하다고 생각한다.
2. App 테스트 종류
테스트 코드의 종류는 2가지가 있다. Unit Test와 Ui Test다.
2-1. Unit Test (단위 테스트)
목적:
- 비즈니스 로직 또는 개별 기능이 예상대로 작동하는지 검증합니다.
- 작은 코드 단위(메서드, 클래스 등)를 테스트합니다.
특징:
- 빠르게 실행되며, 로컬 JVM 환경에서 동작합니다.
- 외부 의존성이 있는 경우 Mocking을 사용합니다.
주요 도구: (JUnit, Mockito, PowerMock 등등)
- JUnit: 자바와 코틀린 코드를 테스트하는 기본 프레임워크.
- Mockito: 의존성을 Mock하여 테스트할 때 사용.
- Truth / AssertJ: 더 가독성 높은 어서션을 제공.
2-2. UI Test (사용자 인터페이스 테스트)
목적:
- UI 요소와 사용자 상호작용을 검증합니다.
- 버튼 클릭, 화면 전환, 텍스트 입력 등 전체 앱 흐름을 테스트합니다.
특징:
- 실제 디바이스나 에뮬레이터에서 실행됩니다.
- 테스트 속도가 느리고, 비동기 처리 및 애니메이션 등 UI 동작을 고려해야 합니다.
주요 도구:
- Espresso: 구글이 제공하는 UI 테스트 프레임워크.
- UIAutomator: 시스템 앱을 포함한 더 넓은 범위를 테스트할 때 사용.
- Compose Test: Jetpack Compose UI를 테스트하는 전용 API.
- 그 외에 Robotium, Calabash, Robolectric 등등이 있다.
3. 예제 코드
build.gradle
dependencies { androidTestImplementation("androidx.test.ext:junit:1.2.1") // 1 testImplementation "com.google.truth:truth:1.1.3" // 2 testImplementation 'org.mockito:mockito-core:5.4.0' // 3 }
1) JUnit 라이브러리
- JUnit 확장을 제공하는 라이브러리입니다.
- 예 : assertEquals(result, 44)
2) Truth 라이브러리 (Google 제공)
용도:
- 테스트의 단언(assertion) 문을 더 가독성 좋고 직관적으로 작성할 수 있도록 도와줍니다.
- 기본 JUnit assertEquals 같은 복잡한 단언문을 대체합니다.
- 예 : assertThat(result).isEqualTo(44)
주요 기능:
- 더 직관적인 문법 제공: 영어 문장처럼 테스트를 작성할 수 있습니다.
- 커스텀 단언문 지원: 사용자 정의 단언문 생성 가능.
- 테스트 오류 메시지 개선: 더 읽기 쉽고 유용한 오류 메시지를 출력.
3) Mockito 라이브러리 (단위 테스트 목킹)
용도:
- 클래스와 객체 간의 의존성을 시뮬레이션(mocking) 하는 라이브러리입니다.
- 단위 테스트 작성 시 네트워크, 데이터베이스 등 외부 의존성을 목(mock) 객체로 대체하여 테스트할 수 있습니다.
주요 기능:
- 목 객체 생성: mock() 메서드를 사용해 의존성을 목으로 생성.
- 행동 정의: when().thenReturn()을 통해 동작 설정.
- 호출 검증: verify() 메서드로 메서드 호출 여부 확인.
CustomCalc (Unit Test 대상)
class CustomCalc : Calculations { override fun sum(num1: Int, num2: Int): Int { return num1 + num2 } override fun minus(num1: Int, num2: Int): Int { return num1 - num2 } } interface Calculations { fun sum(num1: Int, num2: Int): Int fun minus(num1: Int, num2: Int): Int }
CustomCalcTest class
class CustomCalcTest { private lateinit var myCalculation: CustomCalc private lateinit var myCalculationMock: CustomCalc // Mockito 사용 @BeforeEach fun setUp() { myCalculation = CustomCalc() // mockit myCalculationMock = Mockito.mock(CustomCalc::class.java) Mockito.`when`(myCalculationMock.sum(3, 5)).thenReturn(8) } @Test fun sum() { val result = myCalculation.sum(22, 22) assertEquals(result, 44) // JUnit 라이브러리 assertThat(result).isEqualTo(44) // truth 라이브러리 사용 val mockitResult = myCalculationMock.sum(3, 5) assertEquals(8, mockitResult) Mockito.verify(myCalculationMock, times(1)).sum(3,5) } @Test fun minus() { val result = myCalculation.minus(22, 22) assertEquals(result, 0) } }
UnitTest Annotation :
- 수명 주기 관리: @Before, @After, @BeforeClass, @AfterClass
- 조건부 실행: @Ignore, @Disabled
- 예외 테스트: @Test(expected = ...), assertThrows
- 시간 제한: @Test(timeout = ...), assertTimeout
- 반복 테스트: @ParameterizedTest
Junit function들
assertEquals(a, b) 두 값이 같은지 비교 assertEquals(44, result) assertNotEquals(a, b) 두 값이 다른지 확인 assertNotEquals(0, result) assertTrue(condition) 조건이 true인지 확인 assertTrue(result > 0) assertFalse(condition) 조건이 false인지 확인 assertFalse(result < 0) assertNull(value) 값이 null인지 확인 assertNull(someObject) assertNotNull(value) 값이 null이 아닌지 확인 assertNotNull(result) assertSame(a, b) 두 객체가 동일 참조인지 확인 assertSame(obj1, obj2) assertNotSame(a, b) 두 객체가 동일 참조가 아닌지 assertNotSame(obj1, obj2) fail(message) 강제 실패 fail("Test failed!") Google Truth
assertThat(value).isEqualTo(expected) 값이 같은지 확인 assertThat(result).isEqualTo(44) assertThat(value).isNotEqualTo(expected) 값이 다른지 확인 assertThat(result).isNotEqualTo(0) assertThat(value).isTrue() 값이 true인지 확인 assertThat(isValid).isTrue() assertThat(value).isFalse() 값이 false인지 확인 assertThat(isValid).isFalse() assertThat(value).isNull() 값이 null인지 확인 assertThat(result).isNull() assertThat(value).isNotNull() 값이 null이 아닌지 확인 assertThat(result).isNotNull() assertThat(collection).contains(item) 컬렉션이 특정 항목을 포함 assertThat(list).contains("A") assertThat(collection).isEmpty() 컬렉션이 비어 있는지 확인 assertThat(list).isEmpty() assertThat(collection).hasSize(n) 컬렉션 크기 확인 assertThat(list).hasSize(3) Mockito 검증 메서드 (Mock 객체 확인)
verify(mock).method() 메서드가 호출되었는지 확인 verify(calc).sum(3, 5) verify(mock, never()).method() 메서드가 호출되지 않았는지 확인 verify(calc, never()).minus(3, 5) verify(mock, times(n)).method() 특정 횟수 호출 확인 verify(calc, times(2)).sum(1, 1) verify(mock, atLeast(n)).method() 최소 n번 호출 확인 verify(calc, atLeast(1)).sum(3, 5) verify(mock, atMost(n)).method() 최대 n번 호출 확인 verify(calc, atMost(3)).sum(2, 2)