Primary/Android

테스트 코드에서만 접근 가능한 의존성 만들기

해스끼 2023. 9. 30. 15:45

지난 몇 주간 쿠링 안드로이드 앱을 모듈화하고 있다. 여러 이슈가 있었지만 선배님과 함께 잘 풀어나가고 있다. 그 중에서도 오늘은 Gradle의 기능과 관련된 사례 하나를 소개하려 한다.

 

앱에서 사용하는 도메인 클래스를 ``:data:domain`` 모듈로 옮겼다. 동시에 테스트 코드에 있던 도메인 클래스의 mock 코드를 클래스의 정의로 옮겼다.

data class Department(
    val name: String,
    val shortName: String,
    val koreanName: String,
    val isSubscribed: Boolean,
    val isSelected: Boolean,
    val isNotificationEnabled: Boolean,
) {
    companion object {
        fun mock() = Department(
            name = "computer_science",
            shortName = "cse",
            koreanName = "컴퓨터공학부",
            isSubscribed = false,
            isSelected = false,
            isNotificationEnabled = false,
        )
    }
}

그런데 선배님께서 이런 코멘트를 남겨 주셨다.

선배님: 테스트를 위한 코드는 테스트 패키지에서 관리하는 게 좋지 않을까요?

나: Compose Preview용 샘플 데이터로도 쓸 수 있어서, 테스트용 mock이 아니라 fake 데이터 같은 느낌으로 이해하면 되지 않을까요?

선배님: (전략) 프로덕션 코드에 테스트를 위한 함수가 끼어드는 건 주객전도 같아 보입니다. 조금 귀찮더라도 테스트용 데이터는 테스트 쪽에서 만드는 게 좋지 않을까 하는 의견입니다.

나: 그러면 1) 테스트 코드에서만 접근 가능할 것, 2) 여러 모듈에서 접근할 수 있어야 할 것 중 1)번을 중시하는 게 맞다는 말씀이신가요?

선배님: 1)번의 우선순위가 더 높다고 생각해요. 둘 다 충족시키면 제일 좋겠지만... 어떻게 될 것 같은데...

그래서 찾아 본 결과, 이미 Gradle에서 테스트 패키지의 코드를 공유할 수 있는 기능을 지원하고 있었다. 

Test Fixtures

Test Fixtures는 테스트 코드 간 의존성을 공유하는 데 사용될 수 있다. 위의 예시로 설명하자면 ``Notice.mock()`` 함수를 테스트 코드끼리만 공유할 수 있다는 뜻이다.

 

AGP 7.2.0 이상과 Gradle 7.3.3 이상 버전이 요구된다. 요구사항을 먼저 확인하자.

 

이제 실제로 구현해 보자. ``:data:domain`` 모듈에 ``gradle-text-fixtures`` 플러그인을 추가한 후, ``android`` 블럭에 test fixtures 기능을 추가했다.

plugins {
    // ...
    id 'java-test-fixtures'
}

android {
    // ...
    testFixtures {
        enable true
    }
}

이제 ``src\testFixtures\java`` 경로에 공유할 코드를 작성하면 된다.

object KuringFixtures {
    fun noticeFixture() = Notice(
        postedDate = "20220203",
        subject = "2022학년도 1학기 재입학 합격자 유의사항 안내",
        category = "bachelor",
        url = "https://www.konkuk.ac.kr/do/MessageBoard/ArticleRead.do?id=5b4a11b",
        articleId = "5b4a11b",
        isNew = true,
        isRead = false,
        isSubscribing = false,
        isSaved = false,
        isReadOnStorage = false,
        tag = emptyList()
    )
}

의존성 추가

작성한 test fixtures에 의존할 모듈에 다음과 같이 의존성을 추가하자.

testImplementation testFixtures(project(":data:domain"))

이제 테스트 코드에서 test fixtures에 접근할 수 있다!

@Test
fun `insert Notice As Old Test`() {
    val mockData = KuringFixtures.notice()
    // ...
}

자 이제 테스트를 실행해 보면?

에러

Unresolved reference: KuringFixtures

검색해 보니, Android Gradle Plugin에서 Kotlin 코드로 작성된 test fixtures를 지원하지 않는다고 한다. 참고로 Android가 아닌 일반 Kotlin 프로젝트에서는 Kotlin test fixtures를 사용할 수 있다.

 

구글 맞을래요?

 

아래 링크에서 해당 이슈의 진행 상황을 살펴볼 수 있다. 원래 AGP 8.1에서 지원될 예정이었지만, 8.3으로 연기되었다. 일단 8.3.0-alpha06까지는 해결되지 않은 상황.

 

Google Issue Tracker

 

issuetracker.google.com

해결 방법

Java로 작성한 Test fixtures는 정상적으로 사용할 수 있다. 따라서 일단 Java로 작성한 후, 나중에 Kotlin으로 변환하면 된다.

 

Kotlin test fixtures가 지원되면 이 글을 업데이트하겠다.

정리

Test fixtures를 사용하면 테스트 코드에서만 사용할 유틸, 데이터 등을 프로덕션에 노출하지 않고도 여러 모듈 간에 공유할 수 있다. 다만 Android Kotlin 프로젝트에서 지원되지 않는 점이 아쉽다. AGP 8.3.0이 빨리 출시됐으면 좋겠다.