본문 바로가기
어질어질 개발노트/Android

[Android] 안드로이드 앱 품질 향상을 위한 Unit 및 UI 테스트 완벽 가이드

by tia.mom 2025. 1. 15.
반응형

안드로이드 개발에서 테스트는 애플리케이션의 품질을 보장하고 오류를 줄이는 데 중요한 역할을 합니다. 이 가이드에서는 Test-Driven Development(TDD)의 개념과 함께 Unit 테스트와 UI 테스트를 설정하고 실행하는 방법, 의존성 추가, 테스트 작성 시 주의사항 등을 단계별로 소개합니다.


1. 테스트와 TDD 개요

테스트 종류

Unit 테스트

  • 정의: 개별 함수나 클래스의 논리를 테스트하는 데 중점을 둡니다.
  • 목적: 빠르고 독립적인 테스트를 통해 비즈니스 로직을 검증합니다.

UI 테스트

  • 정의: 사용자 인터페이스와 애플리케이션의 상호작용을 테스트합니다.
  • 목적: 사용자가 애플리케이션과 상호작용할 때의 흐름을 확인하고 오류를 방지합니다.

TDD란?

  • Test-Driven Development(테스트 주도 개발): 테스트 코드를 먼저 작성한 후, 이를 통과하는 최소한의 코드를 작성하는 개발 방식입니다.
  • 장점:
    • 높은 코드 품질 유지
    • 디버깅 시간 단축
    • 명확한 요구 사항 반영

2. 의존성 추가

Gradle 파일에 의존성 추가하기

Unit 테스트와 UI 테스트를 실행하려면 적절한 라이브러리를 추가해야 합니다.

build.gradle (모듈 레벨):

dependencies {
    // Unit 테스트
    testImplementation 'junit:junit:4.13.2'
    testImplementation 'org.mockito:mockito-core:4.11.0'

    // AndroidX Unit 테스트
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test:core:1.5.0'

    // UI 테스트
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
    androidTestImplementation 'androidx.test.espresso:espresso-intents:3.5.1'
}

3. TDD로 Unit 테스트 작성하기

TDD에서는 다음의 단계를 반복합니다:

  1. 실패하는 테스트 작성
  2. 테스트를 통과시키는 최소한의 코드 작성
  3. 코드 리팩토링

예제: Calculator 클래스 테스트

Calculator 클래스:

class Calculator {
    fun add(a: Int, b: Int): Int {
        return a + b
    }

    fun subtract(a: Int, b: Int): Int {
        return a - b
    }
}

테스트 코드:

import org.junit.Assert.assertEquals
import org.junit.Test

class CalculatorTest {
    private val calculator = Calculator()

    @Test
    fun `add should return correct sum`() {
        val result = calculator.add(2, 3)
        assertEquals(5, result)
    }

    @Test
    fun `subtract should return correct difference`() {
        val result = calculator.subtract(5, 3)
        assertEquals(2, result)
    }
}

4. TDD로 UI 테스트 작성하기

UI 테스트는 src/androidTest/java 디렉토리에 작성하며, TDD 프로세스를 따릅니다.

예제: Login 화면 테스트

LoginActivity:

class LoginActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)

        val button = findViewById<Button>(R.id.login_button)
        val input = findViewById<EditText>(R.id.username_input)

        button.setOnClickListener {
            val username = input.text.toString()
            Toast.makeText(this, "Welcome $username", Toast.LENGTH_SHORT).show()
        }
    }
}

테스트 코드:

import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.typeText
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import org.junit.Rule
import org.junit.Test

class LoginActivityTest {

    @get:Rule
    val activityRule = ActivityScenarioRule(LoginActivity::class.java)

    @Test
    fun `login button should show welcome message`() {
        onView(withId(R.id.username_input))
            .perform(typeText("John"))
        onView(withId(R.id.login_button))
            .perform(click())
        onView(withText("Welcome John"))
            .check(matches(isDisplayed()))
    }
}

5. 테스트 실행하기

Android Studio에서 실행

  1. Unit 테스트: src/test/java 디렉토리에서 테스트 클래스를 선택하고 실행.
  2. UI 테스트: src/androidTest/java 디렉토리에서 테스트 클래스를 선택하고 실행.

명령어로 실행

Gradle 명령어를 사용해 테스트를 실행할 수도 있습니다:

  • Unit 테스트: ./gradlew test
  • UI 테스트: ./gradlew connectedAndroidTest

6. 테스트 작성 시 주의사항

  1. 단일 책임 원칙 준수: 각 테스트는 하나의 기능만 검증해야 합니다.
  2. 독립성 유지: 테스트는 서로 독립적으로 실행 가능해야 합니다.
  3. 의존성 최소화: 테스트에서 네트워크 호출, 데이터베이스 접근 등 외부 의존성을 Mocking으로 대체하세요.
  4. 명확한 네이밍: 테스트 이름은 검증하려는 동작을 명확히 설명해야 합니다.
  5. 실제 시나리오 테스트: UI 테스트에서는 사용자가 실제로 수행할 작업을 기반으로 작성하세요.
반응형