Android UIテストガイドのEspresso
11440 ワード
Espressoについて Espressoは簡単で使いやすいAndroid UIテストフレームワーク です. Espressoは主に以下の3つの基礎部分から構成されている: Espressoの使用例
の準備を
第一歩build.gradleは次の依存性を追加します.
第二歩android.defaultConfig次の構成を追加
基本的な使い方
ビューを取得 withId方式 withText方式
View動作の実行クリック テキスト内容入力 scrollToスライド
検査ビュービューのテキスト内容をチェック 検査Viewの表示状態
シーンの例:
簡単なログインシーンテスト
ステップアップ法
1.IdlingResourceの使用
通常、私たちの実際のアプリケーションには、ネットワークリクエスト、ピクチャロードなどの非同期タスクがたくさんありますが、Espressoはあなたの非同期タスクがいつ終わるか分からないので、IdlingResourceを借りる必要があります.
ここで注意しなければならないのは、AsyncTaskまたはAsyncTaskCompat方式の非同期タスクであれば、Espressoはすでに処理されており、追加の処理は必要ありません.
ステップ1:依存ライブラリの追加
ステップ2:IdlingResourceインタフェースを定義します.
次に例を示します.
シーン:現在、ユーザーのアイコンが正常に表示されているかどうかをテストする必要があるとします.
Activityコード
SimpleIdlingResourceコード
IdlingResourceTestコード
また、Espressoは実現したCountingIdlingResourceクラスを提供しているので、特に必要がなければCountingIdlingResourceをそのまま使えばよい.
2.カスタムEspresso matcherを作成する
現在、Espressoが提供している方法は、下図に示すように、基本的にテストのニーズを満たすことができます.
カスタムビューのカスタム属性をテストする必要がある場合は、カスタムMatcherを作成できます.
3.アニメーションの処理方法システムアニメーション: アニメーションスレッドの実行中にEspressoテストに与える影響を避けるために、システムアニメーションを閉じることを強くお勧めします.図に示すように、カスタムアニメーション: カスタムアニメーションの場合、開発者は以下のコードを使用してアニメーションのオンとオフを制御できます.
この方法はEspressoテストだけでなく、システムアニメーションのスイッチングイベントをリスニングすることができます.
4.優雅なIntentTest一般的な方式
通常の方法を使用する場合、ユニットテストクラスの下のすべてのテストは、Intentに基づいて起動されたActivityに基づいており、これは明らかに柔軟ではありません.エレガントな方法
5.テストの独立性を保証する
通常、Espressoを使用してUIテストを行う場合、ネットワークやリモートのサービスに関連するものをテストすることは望ましくありません.そのため、Espresso Intent、Mockito for mocking、注射、Dagger 2に依存することができます.要するに、UIレベルではないコンテンツをできるだけ分離します.
たとえば、あるボタンのクリックイベントをテストする必要がありますが、そのボタンをクリックすると、別のActivityにジャンプしますが、他のActivityをテストしたくない場合は、ここでIntentをブロックすることで解決できます.
まず、IntentTest依存ライブラリを追加する必要があります.
InterceptIntentTestサンプルコード
6.testコードの直接コピーと貼り付けを避ける
簡単な例を挙げる.
以上のコードはマッチングリストの条件に合致するitemであり、クリックイベントを実行し、テストも正常であり、同様にこのコードも他のテスト方法にコピーされて使用されている.この場合、adapterのデータソースがcursorまたは他に変更された場合、悲しいことに、多くの場所を修正する必要があると考えてみてください.明らかに、これは合格したCV戦士ではありません.
以前のコードを改装する必要があります
簡単で、変化する可能性のある部分を抽出するだけでいいです.
7.Viewの場所をテストする方法
図に示すように、
8.カスタムエラーログ
図:
関心のあるログ情報だけを表示したい場合は、FailureHandlerをカスタマイズできます.
著者:yonglan.whl
原文を読む
本文は雲栖コミュニティのオリジナル内容で、許可を得ずに転載してはならない.
ViewMatchers - View View .
ViewActions - Views , .
ViewAssertions - Views , .
onView(ViewMatcher) //1. View
.perform(ViewAction) //2. View
.check(ViewAssertion); //3. View
の準備を
第一歩build.gradleは次の依存性を追加します.
androidTestImplementation 'com.android.support.test.espresso:espresso-core:latest.version'
androidTestImplementation 'com.android.support.test:runner:latest.version'
androidTestImplementation 'com.android.support.test:rules:latest.version'
第二歩android.defaultConfig次の構成を追加
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
基本的な使い方
ビューを取得
onView(withId(R.id.my_view))
onView(withText("Hello World!"))
View動作の実行
onView(...).perform(click());
onView(...).perform(typeText("Hello"), click());
onView(...).perform(scrollTo(), click());
検査ビュー
onView(...).check(matches(withText("Hello!")));
onView(...).check(matches(isDisplayed()));
シーンの例:
簡単なログインシーンテスト
@RunWith(AndroidJUnit4.class)
public class LoginUITest {
@Rule
public ActivityTestRule rule=new ActivityTestRule(LogingActivity.class,true);
@Test
public void login(){
//login
onView(withId(R.id.userName)).perform(typeText("Jack"),closeSoftKeyboard());
onView(withId(R.id.password)).perform(typeText("1234"),closeSoftKeyboard());
onView(withText(" ")).perform(click());
//verify
onView(withId(R.id.content)).check(matches(isDisplayed()));
}
}
ステップアップ法
1.IdlingResourceの使用
通常、私たちの実際のアプリケーションには、ネットワークリクエスト、ピクチャロードなどの非同期タスクがたくさんありますが、Espressoはあなたの非同期タスクがいつ終わるか分からないので、IdlingResourceを借りる必要があります.
ここで注意しなければならないのは、AsyncTaskまたはAsyncTaskCompat方式の非同期タスクであれば、Espressoはすでに処理されており、追加の処理は必要ありません.
ステップ1:依存ライブラリの追加
compile 'com.android.support.test.espresso:espresso-idling-resource:latest.version'
ステップ2:IdlingResourceインタフェースを定義します.
public interface IdlingResource {
/**
* IdlingResource
*/
public String getName();
/**
* IdlingResource .
*/
public boolean isIdleNow();
/**
ResourceCallback
*/
public void registerIdleTransitionCallback(ResourceCallback callback);
/**
* Espresso IdlingResource
*/
public interface ResourceCallback {
/**
* , Espresso
*/
public void onTransitionToIdle();
}
}
次に例を示します.
シーン:現在、ユーザーのアイコンが正常に表示されているかどうかをテストする必要があるとします.
Activityコード
public class AvatarActivity extends AppCompatActivity{
private ImageView mAvatar;
public static SimpleIdlingResource sIdlingResource=new SimpleIdlingResource();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_idling_resource);
mAvatar= (ImageView) findViewById(R.id.avatar);
//App ,
sIdlingResource.increment();
//
Glide.with(this).load("https://avatars2.githubusercontent.com/u/2297803?v=3&s=460").into(new GlideDrawableImageViewTarget(mAvatar) {
@Override
public void onResourceReady(GlideDrawable resource,
GlideAnimation super GlideDrawable> animation) {
super.onResourceReady(resource, animation);
// , App
sIdlingResource.decrement();
}
});
}
}
SimpleIdlingResourceコード
public final class SimpleIdlingResource implements IdlingResource {
private final AtomicInteger counter = new AtomicInteger(0);
private volatile ResourceCallback resourceCallback;
@Override
public String getName() {
return "SimpleIdlingResource";
}
/**
* counter 0,
*/
@Override
public boolean isIdleNow() {
return counter.get() == 0;
}
@Override
public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
this.resourceCallback = resourceCallback;
}
/**
* counter
*/
public void increment() {
counter.getAndIncrement();
}
/**
*counter
*/
public void decrement() {
int counterVal = counter.decrementAndGet();
if (counterVal == 0) {
// onTransitionToIdle() , Espresso, 。
if (null != resourceCallback) {
resourceCallback.onTransitionToIdle();
}
}
if (counterVal < 0) {
throw new IllegalArgumentException("Counter has been corrupted!");
}
}
}
IdlingResourceTestコード
@RunWith(AndroidJUnit4.class)
public class IdlingResourceTest {
@Rule
public ActivityTestRule rule=new ActivityTestRule<>(AvatarActivity.class,true);
@Before
public void registerIdlingResource(){
Espresso.registerIdlingResources(rule.getActivity().sIdlingResource);
}
@Test
public void avatarDisplayed(){
onView(withId(R.id.avatar)).check(matches(isDisplayed()));
}
@After
public void unregisterIdlingResource() {
Espresso.unregisterIdlingResources(
rule.getActivity().sIdlingResource);
}
}
また、Espressoは実現したCountingIdlingResourceクラスを提供しているので、特に必要がなければCountingIdlingResourceをそのまま使えばよい.
2.カスタムEspresso matcherを作成する
現在、Espressoが提供している方法は、下図に示すように、基本的にテストのニーズを満たすことができます.
カスタムビューのカスタム属性をテストする必要がある場合は、カスタムMatcherを作成できます.
public static Matcher isMoved() {
return new TypeSafeMatcher() {
@Override
public void describeTo(Description description) {
description.appendText("is moved");
}
@Override
public boolean matchesSafely(View view) {
return ((CustomView)view).isMoved();
}
};
}
3.アニメーションの処理方法
この方法はEspressoテストだけでなく、システムアニメーションのスイッチングイベントをリスニングすることができます.
boolean animationEnabled=true;
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.JELLY_BEAN_MR1){
try {
if (Settings.Global.getFloat(getContentResolver(),Settings.Global.ANIMATOR_DURATION_SCALE)==0.0f){
animationEnabled=false;
}
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
}
4.優雅なIntentTest
@Rule
public ActivityTestRule rule=new ActivityTestRule(MainActivity.class){
@Override
protected Intent getActivityIntent() {
Intent result=new Intent(...);
result.putExtra(...)
return result;
}
};
通常の方法を使用する場合、ユニットテストクラスの下のすべてのテストは、Intentに基づいて起動されたActivityに基づいており、これは明らかに柔軟ではありません.
@Rule
public ActivityTestRule rule=new ActivityTestRule(MainActivity.class,true,false);// Activity
public void myTest(){
Intent result=new Intent(...);
result.putExtra(...);
rule.launchActivity(result);
}
5.テストの独立性を保証する
通常、Espressoを使用してUIテストを行う場合、ネットワークやリモートのサービスに関連するものをテストすることは望ましくありません.そのため、Espresso Intent、Mockito for mocking、注射、Dagger 2に依存することができます.要するに、UIレベルではないコンテンツをできるだけ分離します.
たとえば、あるボタンのクリックイベントをテストする必要がありますが、そのボタンをクリックすると、別のActivityにジャンプしますが、他のActivityをテストしたくない場合は、ここでIntentをブロックすることで解決できます.
まず、IntentTest依存ライブラリを追加する必要があります.
androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'
InterceptIntentTestサンプルコード
@RunWith(AndroidJUnit4.class)
public class InterceptIntentTest {
@Rule
public IntentsTestRule rule=new IntentsTestRule<>(MainActivity.class);
@Before
public void stubCameraIntent(){
// ActivityResult
Instrumentation.ActivityResult result = createImageCaptureActivityResultStub();
// MediaStore.ACTION_IMAGE_CAPTURE, result
intending(hasAction(MediaStore.ACTION_IMAGE_CAPTURE)).respondWith(result);
}
@Test
public void takePhoto_cameraIsLaunched(){
onView(withId(R.id.button_take_photo)).perform(click());
intended(hasAction(MediaStore.ACTION_IMAGE_CAPTURE));
...
}
private Instrumentation.ActivityResult createImageCaptureActivityResultStub() {
// Create the ActivityResult, with a null Intent since we do not want to return any data
// back to the Activity.
return new Instrumentation.ActivityResult(Activity.RESULT_OK, null);
}
}
6.testコードの直接コピーと貼り付けを避ける
簡単な例を挙げる.
onData(allOf(is(instanceOf(Map.class)),hasEntry(equalTo("STR"),is("item:50")))).perform(click());
以上のコードはマッチングリストの条件に合致するitemであり、クリックイベントを実行し、テストも正常であり、同様にこのコードも他のテスト方法にコピーされて使用されている.この場合、adapterのデータソースがcursorまたは他に変更された場合、悲しいことに、多くの場所を修正する必要があると考えてみてください.明らかに、これは合格したCV戦士ではありません.
以前のコードを改装する必要があります
@Test
public void myTest(){
onData(withItemContent("item:50")).perform(click());
}
public static Matcher extends Object> withItemContent(String expectedText) {
....
}
簡単で、変化する可能性のある部分を抽出するだけでいいです.
7.Viewの場所をテストする方法
図に示すように、
8.カスタムエラーログ
図:
関心のあるログ情報だけを表示したい場合は、FailureHandlerをカスタマイズできます.
private static class CustomFailureHandler implements FailureHandler {
private final FailureHandler delegate;
public CustomFailureHandler(Context targetContext) {
delegate = new DefaultFailureHandler(targetContext);
}
@Override
public void handle(Throwable error, Matcher viewMatcher) {
try {
delegate.handle(error, viewMatcher);
} catch (NoMatchingViewException e) {
throw new MySpecialException(e);
}
}
}
@Override
public void setUp() throws Exception {
super.setUp();
getActivity();
setFailureHandler(new CustomFailureHandler(getInstrumentation()
.getTargetContext()));
}
著者:yonglan.whl
原文を読む
本文は雲栖コミュニティのオリジナル内容で、許可を得ずに転載してはならない.