테스트 기본 요소(Fundamentals of Testing)
사용자는 버튼을 누르는 것부터 기기에 정보를 다운로드하는 것에 이르기까지 다양한 수준에서 앱과 상호작용합니다. 따라서 반복적으로 앱을 개발할 때 다양한 사용 사례와 상호작용을 테스트해야 합니다.
앱이 확장됨에 따라 서버에서 데이터를 가져오거나, 기기 센서와 상호작용하거나, 로컬 저장소에 액세스하거나, 복잡한 사용자 인터페이스를 렌더링해야 할 수 있습니다. 앱 다양성을 고려하여 종합적인 테스트 전략을 수립해야 합니다.
반복적으로 코드 만들기 및 테스트
새 기능을 디자인할 때 나타나는 책임 단위를 고려하는 것이 중요합니다. 단위마다 해당하는 단위 테스트를 작성합니다. 단위 테스트는 표준 상호작용, 잘못된 입력, 사용 가능한 리소스가 없는 사례를 비롯한 단위와의 가능한 모든 상호작용을 다뤄야 합니다. (Jetpack 라이브러리 사용 추천)
효과적인 단위 테스트 빌드(Build effective unit tests)
사용자 인터페이스 테스트 자동화(Automate user interface tests)
앱 구성요소 통합 테스트(Test app component integrations)
- Service
- Contents provider
UI 성능 테스트(Test UI performance)
구글 공식 테스팅 샘플코드 깃주소
github.com/android/testing-samples
Espresso
kotlin
@Test
fun greeterSaysHello() {
onView(withId(R.id.name_field)).perform(typeText("Steve"))
onView(withId(R.id.greet_button)).perform(click())
onView(withText("Hello Steve!")).check(matches(isDisplayed()))
}
java
@Test
public void greeterSaysHello() {
onView(withId(R.id.name_field)).perform(typeText("Steve"));
onView(withId(R.id.greet_button)).perform(click());
onView(withText("Hello Steve!")).check(matches(isDisplayed()));
}
UI Automator
kotlin
device = UiDevice.getInstance(getInstrumentation())
device.pressHome()
// Bring up the default launcher by searching for a UI component
// that matches the content description for the launcher button.
val allAppsButton: UIObject = device.findObject(
UiSelector().description("Apps"))
// Perform a click on the button to load the launcher.
allAppsButton.clickAndWaitForNewWindow()
java
device = UiDevice.getInstance(getInstrumentation());
device.pressHome();
// Bring up the default launcher by searching for a UI component
// that matches the content description for the launcher button.
UiObject allAppsButton = device
.findObject(new UiSelector().description("Apps"));
// Perform a click on the button to load the launcher.
allAppsButton.clickAndWaitForNewWindow();
AndroidX 테스트 에서 JUnit4 rules 적용
ActivityTestRule
ActivityScenarioRule 적용
kotlin
@RunWith(AndroidJUnit4::class.java)
@LargeTest
class MyClassTest {
@get:Rule
val activityRule = ActivityScenarioRule(MyClass::class.java)
@Test fun myClassMethod_ReturnsTrue() { ... }
}
java
@RunWith(AndroidJUnit4.class)
@LargeTest
public class MyClassTest {
@Rule
public ActivityScenarioRule<MyClass> activityRule =
new ActivityScenarioRule(MyClass.class);
@Test
public void myClassMethod_ReturnsTrue() { ... }
}
ServiceTestRule
kotlin
@RunWith(AndroidJUnit4::class.java)
@MediumTest
class MyServiceTest {
@get:Rule
val serviceRule = ServiceTestRule()
@Test fun testWithStartedService() {
serviceRule.startService(
Intent(ApplicationProvider.getApplicationContext<Context>(),
MyService::class.java))
// Add your test code here.
}
@Test fun testWithBoundService() {
val binder = serviceRule.bindService(
Intent(ApplicationProvider.getApplicationContext(),
MyService::class.java))
val service = (binder as MyService.LocalBinder).service
assertThat(service.doSomethingToReturnTrue()).isTrue()
}
}
java
@RunWith(AndroidJUnit4.class)
@MediumTest
public class MyServiceTest {
@Rule
public final ServiceTestRule serviceRule = new ServiceTestRule();
@Test
public void testWithStartedService() {
serviceRule.startService(
new Intent(ApplicationProvider.getApplicationContext(),
MyService.class));
// Add your test code here.
}
@Test
public void testWithBoundService() {
IBinder binder = serviceRule.bindService(
new Intent(ApplicationProvider.getApplicationContext(),
MyService.class));
MyService service = ((MyService.LocalBinder) binder).getService();
assertThat(service.doSomethingToReturnTrue()).isTrue();
}
}
AndroidJUnitRunner
Write JUnit tests
kotlin
@RunWith(AndroidJUnit4::class)
@LargeTest
class ChangeTextBehaviorTest {
val stringToBeTyped = "Espresso"
@get:Rule
val activityRule = ActivityTestRule(MainActivity::class.java)
@Test fun changeText_sameActivity() {
// Type text and then press the button.
onView(withId(R.id.editTextUserInput))
.perform(typeText(stringToBeTyped), closeSoftKeyboard())
onView(withId(R.id.changeTextBt)).perform(click())
// Check that the text was changed.
onView(withId(R.id.textToBeChanged))
.check(matches(withText(stringToBeTyped)))
}
}
java
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ChangeTextBehaviorTest {
private static final String stringToBeTyped = "Espresso";
@Rule
public ActivityTestRule<MainActivity> activityRule =
new ActivityTestRule<>(MainActivity.class);
@Test
public void changeText_sameActivity() {
// Type text and then press the button.
onView(withId(R.id.editTextUserInput))
.perform(typeText(stringToBeTyped), closeSoftKeyboard());
onView(withId(R.id.changeTextBt)).perform(click());
// Check that the text was changed.
onView(withId(R.id.textToBeChanged))
.check(matches(withText(stringToBeTyped)));
}
}
Android Test Orchestrator 사용
장점
- Minimal shared state(최소 공유 상태) : 각 테스트는 자체 Instrumentation 인스턴스에서 실행됩니다. 따라서 테스트가 앱 상태를 공유하는 경우 각 테스트 후 이러한 공유 상태 대부분이 기기의 CPU 또는 메모리에서 삭제됩니다.
- Crashes are isolated(비정상 종료 각리됨) : 테스트 하나가 비정상 종료되더라도 자체 Instrumentation 인스턴스만 삭제하므로 모음에 있는 나머지 테스트는 계속 실행됩니다.
각 테스트 후 모든 공유 상태를 기기의 CPU와 메모리에서 삭제하려면 clearPackageData 플래그를 사용하세요.
Mockito
참고
안드로이드 Developer 공식 사이트 developer.android.com/training/testing?hl=ko
'Android > Android Test' 카테고리의 다른 글
[codelab 5.1 -8 9 10]AndroidX 테스트로 ViewModel(LiveData 관찰되는지) 테스트 (0) | 2021.05.03 |
---|---|
[codelab 5.1 - 5 6 7] Android Test 종류, [일반 클래스] Local Unit Test, TDD (0) | 2021.05.03 |
UI Test (with Espresso) (0) | 2021.04.28 |
Android Test관련 실습 예제 및 소스 목록 (1) | 2021.04.26 |
Android Test 디자인 (Droid Knights 2018 발표 내용 정리하기) (0) | 2021.04.24 |