728x90
반응형
SMALL
- dependency 추가
기본으로 추가되어있는 dependency 외에 mockito, truth를 추가하였습니다.
dependencies {
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
// test
androidTestImplementation("org.mockito:mockito-android:2.24.5")
testImplementation 'org.mockito:mockito-inline:2.21.0'
testImplementation "com.google.truth:truth:1.0"
}
- Repository, ViewModel
test할 Repository 와 ViewModel은 다음과 같습니다.
class Repository {
// TEST
val deviceEmg1 = BleDevice(EMG_DEVICE_1, MutableLiveData(false), MutableLiveData(false),null)
val deviceEmg2 = BleDevice(EMG_DEVICE_2, MutableLiveData(false), MutableLiveData(false),null)
val deviceLight1 = BleDevice(LIGHT_DEVICE_1, MutableLiveData(false),null,null)
val deviceLight2 = BleDevice(LIGHT_DEVICE_2, MutableLiveData(false),null,null)
fun getEmg1Connected() = deviceEmg1.connected
fun getEmg2Connected() = deviceEmg2.connected
fun getEmg1Calibrated() = deviceEmg1.calibrated
fun getEmg2Calibrated() = deviceEmg2.calibrated
}
class MeasureViewModel(private val repository: Repository): ViewModel() {
private val emg1Connected: LiveData<Boolean>
get() = repository.getEmg1Connected()
private val emg2Connected: LiveData<Boolean>
get() = repository.getEmg2Connected()
private val emg1Calibrated: LiveData<Boolean>?
get() = repository.getEmg1Calibrated()
private val emg2Calibrated: LiveData<Boolean>?
get() = repository.getEmg2Calibrated()
fun reqCalibration(): Boolean{
var req1 = true
var req2 = true
if(emg1Connected.value == true){
if(emg1Calibrated?.value == true) req1 = false
}else{
req1 = false
}
if(emg2Connected.value == true){
if(emg2Calibrated?.value == true) req2 = false
}else{
req2 = false
}
return (req1 or req2)
}
}
repository의 LiveData에 영향을 받는 변수를 가지는 메서드 reqCalibration()가 test 대상입니다.
메서드가 잘 작동하는지 확인하기 위해, repository의 값을 바꾸며 test할 수 있습니다.
- KoinTest
Koin 사용을 위해 AbstractKoinTest class를 만들고, 상속하여 사용합니다.
abstract class AbstractKoinTest: KoinTest {
@get:Rule
val koinTestRule = KoinTestRule.create{
printLogger(Level.DEBUG)
modules(listOf(repositoryModule, viewModelModule, fragmentModule)) //myModule
}
@get:Rule
val mockProvider = MockProviderRule.create{
clazz-> Mockito.mock(clazz.java)
}
}
- ExampleUnitTest
unitTest이므로 androidTest가 아닌 test폴더에서 하여줍니다.
import androidx.lifecycle.MutableLiveData
import com.google.common.truth.Truth.assertThat
import com.robotnmore.rmfit.viewmodel.MeasureViewModel
import org.junit.Test
import org.junit.Before
import org.koin.test.inject
import org.koin.test.mock.declareMock
import org.mockito.BDDMockito.given
import org.mockito.Mockito.`when`
class ExampleUnitTest: AbstractKoinTest() {
val measureViewModel: MeasureViewModel by inject()
@Before
fun setup(){
}
@Test
fun `EMG 디바이스의 연결, Calibration 상태에 따른 Calibration 요구`(){
// Given
val repository = declareMock<Repository>{
given(getEmg1Connected()).willReturn(MutableLiveData(true))
given(getEmg2Connected()).willReturn(MutableLiveData(true))
given(getEmg1Calibrated()).willReturn(MutableLiveData(true))
given(getEmg2Calibrated()).willReturn(MutableLiveData(true))
}
//`when`(repository.getEmg1Calibrated()).thenReturn(MutableLiveData(false))
// When
val result = measureViewModel.reqCalibration()
// Then
assertThat(result).isFalse()
}
}
위와 같이 간단히 테스트할 수 있습니다.
AbstractKoinTest()를 상속하고,
간단히 viewModel을 주입하여 줍니다.
@Before을 사용하여 Test전에 setup()메서드를 먼저 실행할 수 있습니다.
- @Test
Given-When-Then 패턴으로 나누었습니다.
Given : declareMock과 given을 이용하여 repository를 가짜로 생성해주고, 함수들의 리턴 값을 설정해줍니다.
또는 `when`을 이용하여 설정할 수 있습니다.
When : test할 메서드인 reqCalibration()를 실행합니다.
Then : 결과가 예상과 맞는지 확인합니다.
그다음 해당 class를 run 해주면, 예상과 맞는지 결과를 확인할 수 있습니다.
Test를 통과했다고 하네요 ^^
참고 자료
728x90
반응형
LIST
'Android > 이론' 카테고리의 다른 글
[Java/kotlin] Hex String의 Int 변환 (0) | 2021.03.31 |
---|---|
[안드로이드] RxJava Flowable 알아보기 (위키 번역) (0) | 2021.03.23 |
[안드로이드] Cold flows, Hot channels(번역) (0) | 2021.03.17 |
[안드로이드] Fragment 안의 Fragment 처리(교체, 백스택, Back 버튼 클릭 등) ― parentFragmentManager vs childFragmentManager (1) | 2021.03.02 |