0Pricing
Android Academy · 강의

JUnit을 사용한 단위 테스트

JUnit 4로 빠르고 안정적인 단위 테스트를 작성합니다. @Test, @Before, @After, 단언을 사용하고 InstantTaskExecutorRule로 LiveData를, runTest로 코루틴을 테스트합니다.

JUnit을 사용한 단위 테스트은(는) CoddyKit의 무료 Android Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Android Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Android Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

왜 테스트를 작성해야 하나요?

테스트는 사치가 아니라 여러분의 안전망입니다:

  • 사용자가 발견하기 전에 버그를 찾습니다
  • 자신 있게 리팩터링할 수 있습니다(테스트가 통과하면 문제가 발생하지 않았다는 뜻입니다)
  • 의도한 동작을 문서화합니다
  • 기능을 추가할 때 기존 동작이 깨지는 것을 방지합니다

테스트가 잘된 코드는 설계도 더 나은 경우가 많습니다. 테스트하기 어렵다면 설계가 서로 지나치게 밀접하게 결합되었을 가능성이 큽니다.

Android 테스트 유형

두 가지 범주가 있습니다:

  • 단위 테스트(test/ 폴더) — JVM에서 실행되며 기기가 필요하지 않습니다. 빠르고, 일반적인 Kotlin/Java 로직을 테스트합니다.
  • 계측 테스트(androidTest/ 폴더) — 기기나 에뮬레이터에서 실행됩니다. 더 느리며 Android 전용 코드(Room DB, UI)를 테스트합니다.

비즈니스 로직에는 단위 테스트를 우선 사용하세요. Android API와 상호작용해야 할 때만 계측 테스트를 사용하세요.

JUnit 4 설정

JUnit 4는 Android 프로젝트에 기본으로 포함되어 있습니다. app/build.gradle에 다음 항목을 추가합니다:

// app/build.gradle:
dependencies {
    testImplementation 'junit:junit:4.13.2'
    testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3'
    testImplementation 'androidx.arch.core:core-testing:2.2.0'  // for LiveData
}

첫 JUnit 테스트

src/test/java/에 클래스를 만들고 테스트 메서드에 @Test를 사용해 주석을 지정합니다:

import org.junit.Test
import org.junit.Assert.*

class CalculatorTest {

    private val calc = Calculator()

    @Test
    fun `addition returns correct sum`() {
        val result = calc.add(2, 3)
        assertEquals(5, result)
    }

    @Test
    fun `division by zero throws exception`() {
        assertThrows(ArithmeticException::class.java) {
            calc.divide(10, 0)
        }
    }
}

@Before와 @After

각 테스트 전후에 상태를 설정하고 정리하려면 수명 주기 주석을 사용하세요:

class UserRepositoryTest {

    private lateinit var repo: UserRepository
    private lateinit var fakeDao: FakeUserDao

    @Before
    fun setUp() {
        fakeDao = FakeUserDao()          // fresh instance before each test
        repo = UserRepository(fakeDao)
    }

    @After
    fun tearDown() {
        fakeDao.clear()                  // clean up after each test
    }

    @Test
    fun `getUsers returns all users`() {
        fakeDao.insert(User(1, "Alice"))
        fakeDao.insert(User(2, "Bob"))
        assertEquals(2, repo.getUsers().size)
    }
}

일반적인 검증

JUnit은 Assert.*에 검증 메서드를 제공합니다:

// Equality:
assertEquals(expected, actual)
assertNotEquals(unexpected, actual)

// Null:
assertNull(value)
assertNotNull(value)

// Boolean:
assertTrue(condition)
assertFalse(condition)

// Same object reference:
assertSame(expected, actual)

// Custom message on failure:
assertEquals("User ID should be 1", 1, user.id)

// Exception:
assertThrows(IllegalArgumentException::class.java) {
    User(id = -1, name = "")
}

ViewModel 테스트하기

LiveData를 테스트하려면 InstantTaskExecutorRule을 추가하여 LiveData가 동기적으로 게시되도록 합니다:

class UserViewModelTest {

    @get:Rule
    val instantTaskRule = InstantTaskExecutorRule()

    private val fakeRepo = FakeUserRepository()
    private lateinit var viewModel: UserViewModel

    @Before
    fun setUp() {
        viewModel = UserViewModel(fakeRepo)
    }

    @Test
    fun `users are loaded on init`() {
        fakeRepo.usersToReturn = listOf(User(1, "Alice"), User(2, "Bob"))
        viewModel.loadUsers()

        val result = viewModel.users.value
        assertNotNull(result)
        assertEquals(2, result?.size)
    }
}

코루틴 테스트하기

테스트에서 코루틴 실행을 제어하려면 TestCoroutineDispatcher / StandardTestDispatcher를 사용하세요:

class SyncWorkerTest {

    @get:Rule
    val instantTaskRule = InstantTaskExecutorRule()

    private val testDispatcher = StandardTestDispatcher()

    @Before
    fun setUp() {
        Dispatchers.setMain(testDispatcher)
    }

    @After
    fun tearDown() {
        Dispatchers.resetMain()
    }

    @Test
    fun `sync completes successfully`() = runTest {
        val repo = FakeRepository()
        val worker = SyncUseCase(repo, testDispatcher)
        val result = worker.run()
        assertTrue(result.isSuccess)
    }
}

가짜 객체와 모의 객체 비교

테스트에서 실제 의존성을 대체하는 두 가지 전략입니다:

  • 가짜 객체 — 테스트를 위해 설계된 실제로 동작하는 구현입니다(예: 실제 데이터베이스 대신 메모리 내 목록 사용). 작성하기 쉽고 읽기 쉬우며 라이브러리가 필요하지 않습니다.
  • 모의 객체 — 호출을 기록하고 상호작용을 검증할 수 있는 자동 생성 스텁입니다(Mockito, MockK). 더 강력하지만 지나치게 사용하면 변경에 취약해질 수 있습니다.

간단한 경우에는 가짜 객체를 우선 사용하고, 메서드 호출을 검증해야 할 때 모의 객체를 사용하세요.

가짜 객체 작성하기

가짜 객체는 실제 클래스와 동일한 인터페이스를 구현하지만 메모리 내 저장소를 사용합니다:

interface UserDao {
    fun getAll(): List<User>
    fun insert(user: User)
}

class FakeUserDao : UserDao {
    private val storage = mutableListOf<User>()

    override fun getAll(): List<User> = storage.toList()
    override fun insert(user: User) { storage.add(user) }

    fun clear() { storage.clear() }
}

테스트 이름 규칙

좋은 테스트 이름은 무엇을 테스트하는지와 예상 결과를 설명합니다. 읽기 쉬운 설명을 위해 Kotlin에서는 백틱 함수 이름을 사용하세요:

  • `getUsers returns empty list when no users exist`
  • `login throws exception when password is blank`
  • `add returns correct sum for negative numbers`

패턴: `subject does X when Y`

빠른 확인

JUnit 테스트 클래스에서 @Before의 목적은 무엇인가요?

복습: JUnit 단위 테스트

신뢰할 수 있는 앱은 테스트된 앱입니다:

  • 단위 테스트는 src/test/에 작성하고 JVM에서 실행합니다 — 빠릅니다
  • @Test를 사용해 주석을 지정하고 assertEquals, assertTrue, assertThrows를 사용합니다
  • 설정과 정리에는 @Before / @After를 사용합니다
  • LiveData를 동기적으로 테스트하려면 InstantTaskExecutorRule을 사용합니다
  • 코루틴 테스트에는 runTest + StandardTestDispatcher를 사용합니다
  • 간단한 대체 구현에는 모의 객체보다 가짜 객체를 우선 사용합니다

다음: 상호작용을 검증하기 위한 Mockito 모킹입니다.

자주 묻는 질문

“JUnit을 사용한 단위 테스트” 강의는 무료인가요?

네 — “JUnit을 사용한 단위 테스트” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Android Academy 강의 전체를 잠금 해제할 수 있습니다. Android Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“JUnit을 사용한 단위 테스트”에서 뭘 배우나요?

JUnit 4로 빠르고 안정적인 단위 테스트를 작성합니다. @Test, @Before, @After, 단언을 사용하고 InstantTaskExecutorRule로 LiveData를, runTest로 코루틴을 테스트합니다. 브라우저에서 직접 실행하는 실습 코드로 Android Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Android Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Android Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.

“JUnit을 사용한 단위 테스트” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Android Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Android Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. JUnit을 사용한 단위 테스트
  2. Mockito를 사용한 모의 객체
  3. Espresso를 사용한 UI 테스트
  4. 디버깅과 프로파일링
← Android Academy(으)로 돌아가기