티스토리 뷰

공부/ComposeCamp 2022

Unit 2: 자동테스트

데자와 맛있다 2022. 11. 30. 17:08

자동테스트에 대해

-소프트웨어가 예상대로 작동하는지 확인하는 방법이 테스트이다. 

-자동 테스트는 작성한 코드가 올바르게 작동하는지 확인하는 실제 코드이다.

-테스트 소프트웨어를 사용하면 코드를 공개하기 전에 버그를 미리 제거할 수 있고 변경사항이 도입될때 테스트를 통해 기존 코드를 지속적으로 확인 할 수 있다. 따라서 테스트는 필수적

-수동 테스트를 사용할 수도 있으나 자동 테스트에대해 배워보자

-수동 테스트: 기기와 직접 상호작용하는 사람이 실행함

-자동 테스트: 소프트웨어를 통해 실행되는 테스트

-테스트에 익숙해지면 앱 코드와 함께 테스트도 주기적으로 작성하는게 좋다, 앱에 새 기능을 추가할때마다 테스트를 만들면 추후 앱이 성장할때의 워크로드(리소스 및 코드모음, 혹은 기간내에 시스템에 의해 실행되어야 할 작업 할당량)가 줄어든다, 앱을 수동으로 테스트하지 않아도 되므로 편하고 시간이 절약됨

 

자동테스트가 중요한 이유

-수동테스트는 자동테스트보다 더 많은 노력이 필요하다

-여러 유형의 기기를 고려하는 등 사용자층이 넓은 경우 테스트 진행은 중요하다

-새 코드를 추가할때 기존 기능을 테스트 해야 하는데 이는 기존 테스트가 있는경우에 가능함

-예상치 못한 동작이 있는 상태로 앱이 출시되지 않도록 앱을 고칠수있음

 

 

자동 테스트 유형

  • 로컬 테스트
    • 소수의 코드를 직접 테스트해 확인하는 테스트
    • 함수, 클래스, 속성을 테스트할 수 있음
    • 자바 가상 머신에서 실행, 즉 기기나 에뮬레이터 없이 개발 환경에서 실행된다
    • 개발자 컴퓨터에서 실행된다
    • 리소스를 적게 먹기때문에 (오버헤드가 매우 낮으므로) 제한된 리소스에서 빠르게 실행 가능
    • 안드로이드 스튜디오에서 로컬테스트를 자동으로 실행할 수 있음
  • 계측 테스트
    • 안드로이드 개발에서 계측 테스트는 UI 테스트를 의미함
    • 안드로이드와 플랫폼 API 및 서비스에 종속된 앱 일부를 테스트
    • 앱이나 앱 일부를 실행하고 사용자 상호작용을 시뮬레이션하여 앱이 적절히 반응했는지 확인함
    • 실제 기기, 에뮬레이터에서 테스트가 진행됨
    • 계측 테스트를 실행하면 테스트 코드는 일반 안드로이드 앱처럼 자체 안드로이드 애플리케이션 패키지(APK)로 빌드된다. 
      • APK: 기기나 에뮬레이터에서 앱을 실행하는데 필요한 파일과 모든 코드가 포함된 압축 파일
    • 빌드 후 기기 혹은 에뮬레이터에 APK가 설치된다 그다음 테스트가 진행된다

로컬테스트 해보기

1. 앱코드 준비

로컬 테스트는 앱 코드에서 직접 메서드를 테스트하므로 테스트할 메서드는 클래스 및 메서드에서 사용할 수 있어야 함

 

-calculateTip()

private fun calculateTip(
    amount:Double,//낸 돈
    tipPercent: Double=15.0,//기본 팁값 15%
    roundUp: Boolean//팁값 반올림 할지 말지
) : String {//이 함수의 반환은 String
    var tip = tipPercent / 100 * amount //팁값
    if(roundUp)//roundUp이 true면 반올림해서 tip을 업데이트
        tip=kotlin.math.ceil(tip)
    return NumberFormat.getCurrencyInstance().format(tip)
}

위의 함수를 테스트해보자

 

현재 calculateTip()이 private이므로 테스트에서 엑세스 할수없다

그래서 internal로 바꾼다

 

그리고 @VisibleForTesting 주석을 calculateTip()에 추가한다

-@VisibleForTesting : 메서드가 공개되지만 테스트 목적으로만 공개됨을 표시한다

 

변경 결과는 아래와 같다

@VisibleForTesting
internal fun calculateTip(
    amount:Double,//낸 돈
    tipPercent: Double=15.0,//기본 팁값 15%
    roundUp: Boolean//팁값 반올림 할지 말지
) : String {//이 함수의 반환은 String
    var tip = tipPercent / 100 * amount //팁값
    if(roundUp)//roundUp이 true면 반올림해서 tip을 업데이트
        tip=kotlin.math.ceil(tip)
    return NumberFormat.getCurrencyInstance().format(tip)
}

 

2. 테스트 클래스 만들기

-테스트 클래스는 app/src/test/java/패키지이름/앱이름 에 작성한다

위 이미지에서 표시한 부분에 우클릭-> New-> Kotlin Class/File 선택

 

테스트 클래스의 파일 이름을 정한다

 

3. 테스트 작성

앞에서 테스트 대상으로 정한 calculateTip()을 호출하고 걔가 반환한 값이 예상값과 일치하는지 확인하는 코드를 쓴다

자동 테스트 작성에 대해 알아야 할 몇가지 사항이 있다. 아래는 로컬, 계측 테스트 모두에 적용되는 개념이다

  • 메서드 형태로 자동 테스트를 작성해야 함
  • 메서드에 @Test 어노테이션을 달아야 함, 이렇게 해야 컴파일러에 메서드가 테스트 메서드임을 알리고 그에 맞게 적절히 메서드가 실행된다
  • @Test 어노테이션은 import org.junit.Test
  • 이름에 테스트의 테스트 내용과 예상 결과가 명확히 설명되어 있는지 확인한다
  • 테스트 메서드는 일반 메서드와 같은 로직을 사용하지 않음 항목이 구현되는 방식보다 지정된 입력과 그 예상 출력이 정확한지가 중요하다, 즉 테스트 메서드는 앱 UI혹은 로직이 올바르게 돌아가는지 어설션하는 일련의 명령만 실행하도록 만들어야 함
  • 테스트는 특정 조건이 충족 되었나 확인하는데 사용하는 어설션 으로 끝난다, 어셜션은 이름에 assert가 있는 메서드 호출의 형태로 제공된다(이름에 assert드간다고) 예를들어 assertTrue()라는 어설션은 테스트에 쓰이고 실제 테스트 외 코드에서는 거의 안쓰임
  • 어셜션을 만드는 것은 일반적으로 자동 테스트의 최종 목표이다 앞서 말했듯 어셜션은 일반 코드에서는 흔히 사용되지 않음, 어셜션이라는 애를 써서 예측값과 실제결과가 동일한지 어쩐지 비교를 하는거임
  • 예측값과 실제 결과값이 동일한지 확인하는것은 JUnit라이브러리의 assertEquals()메서드를 사용
    • JUnit라이브러리에서는 어설션이 많이 있다 일반적으로 자주 쓰이는 어셜션은 아래와 같음
      • assertEquals()
      • assertNotEquals()
      • assertTrue()
      • assertFalse()
      • assertNull()
      • assertNotNull()
      • assertThat()
      • 자세한 내용은 여기로 https://developer.android.com/reference/junit/framework/Assert?authuser=1&hl=ko

자 이제 테스트를 작성하자

서비스 비용이 10달러이고 팁이 20%인 값이 들어갔을때 팁이 잘 나오나 테스트하는 메서드를 만든다

예상되는 결과는 2달러다

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

class TipCalculatorTests {
    @Test
    fun calculate_20_percent_tip_no_roundup(){
        //calculateTip에 매개변수로 보낼 값 세가지 amount, tipPercent, roundUp
        val amount=10.00
        val tipPercent=20.00
        val expectedTip="$2.00"//결과로 반환되어야 할 값

        val actualTip= calculateTip(amount=amount, tipPercent=tipPercent, roundUp = false)

        assertEquals(expectedTip,actualTip)
    }
}

 

4. 테스트 실행

작성한 테스트를 실행하자

 

위 이미지를 보면 클래스 이름옆에는(7번줄) 초록 화살표 두개가 있고 함수이름 옆에는(9번줄) 화살표 하나가 있음

이 화살표를 눌러서 테스트를 실행함

클래스 옆 화살표 누르면 이 클래스에 있는 메서드를 한방에 다 실행하고

메서드 옆 화살표 누르면 그 메서드 하나만 실행함

클래스 옆 화살표 누르면 위 처럼 나옴

Run 'TipCalculatorTests'를 눌러보자

 

테스트에 실패하면 이렇게 뜬다

아래 Run창을 보니 테스트 실제 값이 2원으로 나옴^^ 아마 calculateTip에서 이 시스템의 위치에 맞게 값을 변경하는

getCurrencyInstance()

를 사용했기 때문으로 보인다

에뮬레이터에서 실행했을땐 걔의 시스템상 위치는 미쿡인데 지금 이게 로컬 테스트코드는 내 컴퓨터에서 실행되잖음?

내 컴퓨터 위치는 한국이죠? 그래서 이렇게 나오는듯ㅋㅋ

테스트코드를 변경했다

이렇게 테스트 통과하면 초록색으로 뜸


계측 테스트 작성

 

1. 테스트 클래스 만들기

 

아까 로컬 테스트 만들때랑 다른곳임!! 

로컬테스트는 src/test 여기 만들고

계측 테스트는 src/androidTest 여기 만들어야함!!!

그다음 위 이미지에 표시한곳 우클릭 하고 새 코틀린 클래스 파일 만들기 한다

New->Kotlin Class/File

 

이름을 정하자

 

2. 테스트 작성

계측 테스트 코드랑 로컬 테스트 코드는 매우 다름

왜냐면 계측 테스트는 UI의 실제 인스턴스를 테스트하기 때문임

  • androidTest 디렉터리 안에서 @Test 어노테이션: 계측 테스트를 의미함
  • test디렉터리에서 @Test 어노테이션: 로컬 테스트 의미함

UI 를 테스트 해야하므로 UI구성요소를 불러오고 UI구성요소에 엑세스 해야함

UI 구성요소는 composeTestRule을 통해 노드로 엑세스 한다

노드로 엑세스하는 일반적인 방법은 onNodeWithText() 메서드를 사용해 특정 텍스트가 포함된 노드에 엑세스 하는것임

onNodeWithText() 메서드를 사용해 TextField컴포저블에 엑세스하자 

   composeTestRule.onNodeWithText("Tip (%)").performTextInput("20")

 

위와 같은 코드를 사용하면 Tip (%) 라고 적혀있는 컴포저블(노드)에 20이라는 값 입력하도록 UI 엑세스 하게됨

 

   composeTestRule.onNodeWithText("Tip Amount: $2.00").assertExists()

위와 같은 코드를 사용하면 Tip Amount: $2.00 이라는 문자열이 적혀있는 노드(컴포저블?) 가 존재하나 확인하는거임

import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performTextInput
import com.example.tiptime.ui.theme.TipTimeTheme
import org.junit.Rule
import org.junit.Test

class TipUITests {
    @get:Rule
    val composeTestRule= createComposeRule()

    @Test
    fun calculate_20_percent_tip() {
        composeTestRule.setContent {
            TipTimeTheme {//UI테스트를 위해 UI부분을 불러옴
                TipTimeScreen()
            }
        }
        composeTestRule.onNodeWithText("Cost of Service") //이 문자열 적혀있는 TextField에 엑세스함
            .performTextInput("10")//접근한 TextFiled에 10이라는 값을 입력하도록 만듦
        composeTestRule.onNodeWithText("Tip (%)").performTextInput("20")

        composeTestRule.onNodeWithText("Tip Amount: ₩2").assertExists()//이런 내용이 적혀있는게 있나 확인
    }

}

전체 코드는 이렇다

 

3. 테스트 실행

실행 방법은 로컬 테스트랑 같다

각 선언 옆에 있는 화살표를 눌러 전체 테스트나 아니면 개별 테스트 하면됨

근데.. 이거 할때 방화벽 허용 해야됨 ㅠㅠ 나는 실수로 취소눌러서 안됨..

 

 

-참고 사이트

https://developer.android.com/codelabs/basic-android-kotlin-compose-write-automated-tests?authuser=1&hl=ko&continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fandroid-basics-compose-unit-2-pathway-3%3Fhl%3Dko%26authuser%3D1%23codelab-https%3A%2F%2Fdeveloper.android.com%2Fcodelabs%2Fbasic-android-kotlin-compose-write-automated-tests#2 

 

자동 테스트 작성  |  Android 개발자  |  Android Developers

이 Codelab에서는 자동 테스트와 이 테스트가 중요한 이유 및 작성 방법을 알아봅니다.

developer.android.com

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함