일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- SWIFTUI
- 인앱결제
- Android
- Reactive
- GCP
- MediaSession
- RxKotlin
- MediaPlayer
- mysql
- MotionLayout
- liveData
- paging
- Koin
- android13
- 동영상
- mvvm
- junit
- Observable
- Kotlin
- PagingLib
- google play
- rx
- list
- 테스트 자동화
- databinding
- Android 13
- Animation
- SwiftUI Tutorial
- node
- node.js
- Today
- Total
봄날은 갔다. 이제 그 정신으로 공부하자
테스트 자동화 어떻게 만들까? 본문
Unit 테스트를 시작하기 전에…
해당 글은 Unit 테스트 기능을 개발 초기에 마주하는 문제에 대해 간단하게 기술합니다.
해당 글은 테스트 자동화 두번째 글이므로 이전 글을 읽지 않은 분은 이전 글을 읽고 오시면 감사합니다.
첫번째 난관
테스트 자동화를 위해 테스트 기능을 개발하려고 마음 먹으면 “제일 먼저 마주하는 문제가 무얼 테스트해야 하지?”
테스트를 구분해야 합니다. “UNIT 테스트”와 “UI 테스트”로!
이거 구분 없이 테스트 기능을 개발하면 이상한 테스트 코드를 개발하게 되고 많은 유지보수 비용을 꾸준히 지불하다가 결국 테스트 코드를 버리게 됩니다.
UNIT 테스트는 UI 없이 해당 기능이 제대로 동작하는지 테스트 하는 것이고 UI 테스트는 UI가 시나리오대로 동작하는지 테스트 하는 것 입니다.
UNIT 테스트
UNIT 한개에 함수 한개가 될 수도 있고 함수 여러개가 한개의 UNIT이 될 수도 있습니다. (요건 이후에 코드와 같이 설명 들어갑니다.) 테스트 기능 개발 시, UNIT이 기대한대로 동작하는지 다양한 값을 넣어서 테스트를 진행할 수 있습니다.
UI 테스트는
UI가 시나리오대로 동작하는지 확인하는 테스트로 UI 시나리오 문서가 있는 경우 이를 참고해서 테스트 기능 개발이 가능하지만 UI 시나리오 문서가 없거나 있더라도 현실과 다른 경우가 더 많으므로 UI 테스트 기능 개발을 빌미로 UI 시나리오를 만드는 것이 좋습니다. (무언가 이상해도 이쪽에서는 정상입니다.)
이제 “UNIT 테스트”와 “UI 테스트”로 테스트를 구분할 수 있게 되었습니다.
테스트 자동화가 도입되지 않은 회사라면 “UNIT 테스트”를 우선 개발하는 것이 좋습니다.
두번째 난관
UNIT 테스트를 개발하려고 하는데 어떤 것을 UNIT 테스트로 개발해야 하지?
쉽게 생각하면 됩니다. 배포할 때 제일 불안한 것 우선으로 개발하면 됩니다.
대부분 “서버와의 통신이 정상적으로 되는지?”, “넘겨 받은 값을 처리할 때 제대로 처리되는지?”, “그걸 화면에 제대로 표시되는지?”를 생각하게 되는데, 이걸 정리하면 아래와 같습니다.
“서버와의 통신이 정상적으로 되는지?”
API 테스트 UNIT 기능을 만들어서 확인 가능합니다.
한개 UNIT에서 한개의 API를 테스트할수도 있고 연관된 API인 경우, 한개 UNIT에서 여러개의 API를 테스트 하는 것도 괜찮습니다.
API 호출 시 다양한 호출 시나리오와 그에 맞는 결과 값을 미리 정하고 값들이 제대로 내려오는지 확인하는 기능을 만들면 됩니다.
테스트한 API가 많은 경우, 한개의 UNIT이 아닌 성격별로 묶인 여러개의 UNIT을 만드는 것이 좋습니다.
한개 UNIT에서 너무 많은 API를 테스트하는 경우, 에러 하나 때문에 전체 API UNIT 테스트가 지연될 수 있기 때문 입니다.
“넘겨 받은 값을 처리할 때 제대로 처리되는지?”
이 부분은 비지니스 로직에 대한 부분으로 MVC 또는 MVVM에서 M(Model)에 해당하는 부분입니다.
Model 부분을 그대로 UNIT 테스트로 만들면 됩니다.
하지만 많은 코드가 현실적인 문제와 기타 여러 이슈등으로 MVC 또는 MVVM 규칙을 제대로 지키지 못하고 있습니다.
비지니스 로직 중간 중간에 UI에 해당하는 Activity가 튀어나오고 Intent가 튀어나오고, Broadcast Receiver가 튀어 나오면 답 안나옵니다.
이 때문에 비지니스 로직 UNIT 테스트를 포기하는 경우가 많은데, 아주 바람직한 현상입니다.
포기하기 보다는 테스트 기능 개발을 핑계로 기존 코드를 MVC 또는 MVVM 구조로 리팩토링하는 것을 추천 드립니다.
굳이 리팩토링할 필요까지는 없습니다.
JUNIT만으로 대부분의 처리가 가능하지만 부족한 경우, Mokito or PowerMock을 사용을 추천 드립니다.
“그걸 화면에 제대로 표시되는지?”
이부분은 “UI 테스트”에 해당하는 부분 입니다.
화면 처리 쪽은 UI 테스트 기능을 개발하는 “내일의 나”에게 넘기면 됩니다.
아래와 같은 경우가 있습니다.
로그인 기능을 수행하면 약관 동의가 나오고 약관 동의를 완료하면 메인 아이템들을 보여줄 때 기능은 어떻게 UNIT로 개발해야 하는지?
로그인 API, 약관동의 API, 메인 아이템 리스트 API는 한개의 UNIT 테스트로 분리하고,
해당 시나리오는 UI 테스트에서 시나리오로 테스트하면 됩니다.
세번째 난관
JUNIT 라이브러리는 어떻게 추가하지?
쉽습니다. 아래와 같이 build.gradle에 추가하면 됩니다.
defaultConfig {
…
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
dependencies {
testImplementation 'junit:junit:4.12'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
androidTestImplementation 'com.android.support.test:runner:0.5'
androidTestImplementation 'androidx.test:rules:1.3.0-beta01'
…
}
네번째 난관
UNIT 테스트 기능 개발은 어떻게 하지?
우선 androidTest 폴더를 만듭니다.
그리고 하위에 구상한대로 폴더를 아름답게 만든 후, class를 생성해주면 됩니다.
저는 일단 java class로 생성했는데 다음부터는 kotlin class로 하겠습니다.
몇가지 중요한 어노테이션을 제외하고는 일반적인 class 사용법과 동일하다고 보면 됩니다.
@RunWith(JUnit4.class)
@FixMethodOrder(MethodSorters.JVM)
public class SampleTest {
…
}
class 위의 어노테이션을 잘 보시면 됩니다.
“@FixMethodOrder(MethodSorters.JVM)” 어노테이션이 있는데 이부분은 한개 테스트 UNIT(class)에 여러개의 테스트 항목(method)이 있을 때 순서를 보장하기 위한 옵션 입니다.
선언하지 않으면 마구잡이로 실행되어 의도치 않은 결과나 나올 수 있습니다.
FixMethodOrder는 아래와 같이 3가지가 있습니다.
- MethodSorters.DEFAULT: 함수의 hashcode 정렬 순서대로 실행
- MethodSorters.JVM: class에 속한 모든 method를 가져오는 getDeclaredMethods()에서 가져온 method의 순서
- MethodSorters.NAME_ASCENDING: 함수 이름순 정렬 순서대로 실행
@RunWith(JUnit4.class)
@FixMethodOrder(MethodSorters.JVM)
public class SampleTest {
…
@Before
public void init(){
…
}
@After
public void final(){
…
}
@Test(timeout = 7000)
public void testA() {
…
}
…
}
@Before 어노테이션은 테스트가 실행되기 전에 우선 실행되는 어노테이션이고
@After 어노테이션은 테스트가 완료된 후 실행되는 어노테이션 입니다.
@Test 어노테이션은 테스트를 실행하는 함수라는 뜻 입니다.
timeout의 의미는 해당 테스트 함수가 7초 내에 완료되어야 정상이라는 뜻 입니다.
Timeout 옵션이 붙은 이유는 네트워크 테스트의 경우, 정해진 시간보다 오래 걸리는 경우, 테스트 실패로 간주하기로 정했기 때문 입니다.
다섯번째 난관
유효성 검사는 어떻게 하지?
Assert를 사용하면 됩니다.
Assert.assertNotNull(instance); // NULL이 아닌 경우 유효함
Assert.assertEquals(a, b); // 두 값이 같은 경우 유효함
Assert.fail(); // 무조건 실패
Assert.assertThat(a, Matchers(…)). // Mathers 재정의를 통해 비교, 포함 등 다양한 유효성 체크가 가능합니다.
주의, 네트워크와 같이 비동기 처리의 경우 호출 후 바로 끝나기 때문에 응답이 올때까지 Thread.sleep(timeout);을 통해 대기해야 합니다.
마무리
JUNIT 라이브러리는 현재 5 버전까지 나와 있으며 저는 4 버전을 사용하고 있습니다.
나중에 기회가 되면(안한단 얘기임.) 5버전으로 UNIT 테스트 예제를 만들어 공유하겠습니다.
'학습' 카테고리의 다른 글
MotionLayout - xml 구성요소 (0) | 2020.11.25 |
---|---|
MotionLayout - overview (0) | 2020.11.25 |
UI Test 적용하기 (0) | 2020.11.25 |
우선 UNIT Test부터 적용하기 (0) | 2020.11.25 |
조금 더 개발에 집중하기 위한 테스트 자동화 검토 (0) | 2020.11.25 |