Grusie 안드로이드 개발 기술 블로그

[Android] 테스트 코드 작성하기(단위테스트 - unit test) 본문

안드로이드 개발

[Android] 테스트 코드 작성하기(단위테스트 - unit test)

grusie 2024. 4. 3. 13:48
728x90
반응형
SMALL

원하는 기능들을 어느정도 만들 수 있게 된 이후로, 이것저것 눈을 돌리게 되는 거 같다. 물론 테스트라고 하는 것은 매우 중요한 것이기에, 일찍부터 알아두는 것이 좋으나 그럴 여력이 되지 못했었다. 회사 프로젝트에도 테스트코드가 작성되어 있지 않았기에 독학을 하게 되었다.

 

테스트 코드를 작성해는 이유

테스트 코드는 특정 로직을 테스트하면서 기능의 문제나 오류를 찾아내 주는 코드를 뜻한다.

테스트 코드를 작성하지 않았던 사람들은 테스트를 이렇게 진행했을 것이다.

  1. 앱 실행
  2. 오류 발생
  3. 로그를 찍어 오류 파악
  4. 다시 수정 후 앱 실행

이 과정을 반복하면서 오류를 해결했을 것이다.

프로젝트의 규모가 커지면서, build 시간도 오래 걸리기에 비효율적인 작업이 될 것이다.

 

안드로이드에서 테스트 코드의 종류는 크게 2가지가 unit testui test이다.

  • unit test - 로직을 테스트 하는 코드
  • ui test - ui의 동작을 테스트 하는 코드

이번 시간에는 unit test에 대해 다뤄보려고 한다.

 

Unit Test 코드 작성

안드로이드 프로젝트에서 Unit Test를 작성하기 위해서는 안드로이드 프로젝트의 기본으로 생성되는 test라고 되어있는 패키지에 작성을 해주면 된다.

테스트 작성 코드가 들어있는 패키지

※ 만약 Test 패키지가 없을 경우 참고

https://ding-dong-in-future.tistory.com/275

 

Android - Test 디렉터리 생성하기

( ^^ 몰아서 많은걸 하려니 뒤돌면 까먹게 된다 ㅜㅜ ) 원래 새 프로젝트를 생성할 때, 아래와 같이 자동으로 만들어지기는 하지만, 내가 실습하는 강의에서는 테스트 디렉토리부터 만들도록 진

ding-dong-in-future.tistory.com

class ExampleUnitTest {
    @Test
    fun addition_isCorrect() {
        assertEquals(4, 2 + 2)
    }
}

기본으로 작성 되어 있는 코드

- 함수에 @Test 어노테이션을 달아서 테스트 함수를 만들 수 있다.

- assertEquals()를 통해, 4와 2+2가 같은지 확인하는 테스트 코드이다.

- Assert와 관련한 함수들은 junit 라이브러리를 추가하면 사용할 수 있는데, 안드로이드 프로젝트를 생성하면 자동으로 추가된다.

- Assert를 검색하면 다양한 함수들이 나오는데, 상황에 맞게 사용하면 된다. 구조가 간단해서 어렵지 않게 사용할 수 있을 것이다. ex) assertTrue, assertNotNull, assertFalse...

실사용

class PolicyInfoTest {

    private lateinit var policyService: PolicyService
    private val testDispatcher = StandardTestDispatcher()
    private val testScope = TestScope(testDispatcher)

    @OptIn(ExperimentalCoroutinesApi::class)
    @Before
    fun setUp() {
        val client = OkHttpClient.Builder().apply {
            connectTimeout(5, TimeUnit.SECONDS)
            writeTimeout(5, TimeUnit.SECONDS)
            readTimeout(5, TimeUnit.SECONDS)
            retryOnConnectionFailure(true)
            addInterceptor(HttpLoggingInterceptor().apply {
                level = HttpLoggingInterceptor.Level.BODY
            })
        }.build()

        val retrofit = Retrofit.Builder()
            .baseUrl("https://www.youthcenter.go.kr/opi/")
            .addConverterFactory(
                TikXmlConverterFactory.create(
                    TikXml.Builder().exceptionOnUnreadXml(false).build()
                )
            )
            .client(client)
            .build()

        policyService = retrofit.create(PolicyService::class.java)
    }
    //레트로핏 세팅

    @Test
    fun getPolicyListTest() = testScope.runTest {
        val policyList = policyService.getPolicyList(apiKey = BuildConfig.POLICY_API_KEY)

        Assert.assertNotNull(policyList)
    }
}

이런식으로 사용할 수 있다.

 

@Before 어노테이션을 활용해서 Test를 진행하기 전에 필요한 세팅들을 할 수 있으며, 코루틴을 사용하기 위해서, CoroutineTest 의존성을 추가하였다.

COROUTINE_TEST = "org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.COROUTINE_TEST}"

 

@After에서 테스트가 끝난 뒤 처리를 할 수 있다. ex) 코루틴 종료 등

https://tech.kakao.com/2021/11/08/test-code/

 

테스트 코드 한 줄을 작성하기까지의 고난

- 이 글에서 설명한 내용은  if(kakao)2021 에서 보실 수 있습니다. 안녕하세요. 창작자앱개발파트의 Ronda입니다. 창작자 앱 개발파트에서 브런치와 티스토리 안드로이드 앱을 개발하고 있습니다.

tech.kakao.com

카카오 기술 블로그에 나와 있듯이, @get:Rule 어노테이션을 활용하여, 전체에서 사용 가능한 rule을 만들어서 처리하려고도 하였으나, TestCoroutineDispatcher()가 deprecated되어, StandardTestDispatcher를 사용하였기에, 그냥 패스하였다.

 

후기

실제로 Ui에서 동작을 시키는 것에 비해서, 빌드 속도가 빠르고, 실제로 잘 동작하는지, 목업을 만들어서 활용할 수 있다는 점에서 장점을 느꼈다. 미리 여러 개의 테스트 케이스들을 만들어두고 활용을 하면, 문제가 거의 발생하지 않도록 개발을 할 수 있겠다라는 생각을 하였다.

아직 많이 부족하지만, 꾸준히 공부해봐야겠다.

반응형
LIST