使用 Espresso 进行测试 - 第 2 部分(Espresso 和边缘案例)
Espresso 和边缘案例
上一篇文章设置和基础知识介绍了测试和设置环境的基础知识。下一步是测试各种技术来测试各种 android 视图,如 toast、字体、意图、网络调用等。本教程涵盖了使用 espresso 测试的边缘情况(如运行时权限、活动结果等)。
测试 ListView 或 RecyclerView
ListView 或 Spinner 使用AdapterView,在运行时显示来自适配器的数据。因此,与其他视图不同,adapterview不会同时显示所有列表项,这意味着onView不会找到当前未加载的视图。
onData()专门用于在对给定位置执行任何操作之前将所需的列表项置于焦点之中。
// click on 3rd position
// where the type of data source is string
onData(allOf(is(instanceOf(String.class)))).atPosition(2).perform(click());
// select view with text "item 3"
onData(allOf(is(instanceOf(String.class)), is("item 3"))).perform(click());
要执行单击RecyclerView。需要espresso-contrib依赖项,它提供RecyclerView特定的方法,如下所示:
// verify the visibility of recycler view on screen
onView(withId(R.id.news_frag_recycler_list)).check(matches(isDisplayed()));
// perform click on view at 3rd position in RecyclerView
onView(withId(R.id.news_frag_recycler_list))
.perform(RecyclerViewActions.actionOnItemAtPosition(3, click()));
使用自定义意图启动活动
要启动一个活动, ActivityTestRule实例需要一个 Intent 对象,并且应用ActivityTestRule的重载版本。
ActivityTestRule(SingleActivityFactory<T> activityFactory, boolean initialTouchMode, boolean launchActivity)
launchActivity为false表示测试不会自动启动该活动。请参阅实现:
@Rule
public ActivityTestRule<MainActivity> activityTestRule =
new ActivityTestRule<MainActivity>(MainActivity.class,true,false /*lazy launch activity*/){
@Override
protected Intent getActivityIntent() {
/*added predefined intent data*/
Intent intent = new Intent();
intent.putExtra("key","value");
return intent;
}
};
@Test
public void customizeIntent(){
// note instead of null, an intent object can be passed
activityTestRule.launchActivity(null);
}
处理 Marshmallow 运行时权限模型
为了增强数据和关键资源的安全性,Android Marshmallow 及更高版本会在应用程序运行时告知用户应用程序使用的资源。其中一些资源将是存储、联系人、位置和其他硬件资源,如传感器、摄像头等。
因此,为了进行测试,需要首先授予运行时权限,最好在使用@Before注释的方法中授予:
@Before
public void grantPhonePermission() {
// In M+, trying to call a number will trigger a runtime dialog. Make sure
// the permission is granted before running this test.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getInstrumentation().getUiAutomation().executeShellCommand(
"pm grant " + getTargetContext().getPackageName()
+ " android.permission.READ_EXTERNAL_STORAGE");
}
}
使用上下文进行初始化
通常在使用库之前需要一个上下文实例来设置库,因此可以从InstrumentationRegistry实例中检索上下文实例。
@Rule
public ActivityTestRule<NewsActivity> activityTestRule =
new ActivityTestRule<>(NewsActivity.class);
@Before
public void init(){
Context context = InstrumentationRegistry.getTargetContext();
SomeLib.initialize(context); // like fresco, firebase etc
}
测试 Toast 可见性
Toast 是浮动消息,在当前屏幕上向用户显示。要自定义 Toast 的外观,请使用以下代码并仔细注意导入语句。
package com.pavneet_singh;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;
import static android.support.test.espresso.action.ViewActions.typeText;
import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withHint;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import android.support.test.espresso.contrib.RecyclerViewActions;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import com.pavneet_singh.espressotestingdemo.R;
@RunWith(AndroidJUnit4.class)
public class MainActivityTest {
// To launch the mentioned activity under testing
@Rule
public ActivityTestRule<MainActivity> mActivityRule =
new ActivityTestRule<>(MainActivity.class);
@Test
public void testButtonClick() {
// enter name
onView(withId(R.id.editTextName)).perform(typeText("Pavneet"), closeSoftKeyboard());
// clear text
onView(withText("Clear")).perform(click());
// check hint visibility after the text is cleared
onView(withId(R.id.editTextName)).check(matches(withHint("Enter Name")));
onView(withId(R.id.editTextName)).check(matches(isDisplayed()));
onView(withId(R.id.editTextName))
.perform(RecyclerViewActions.actionOnItemAtPosition(3, click()));
// check toast visibility
onView(withText("Pavneet Toast")).
inRoot(withDecorView(not(is(activity.getWindow().getDecorView())))).
check(matches(isDisplayed()));
}
}
检查 ScrollView 中的视图可见性
ScrollView 可以垂直或水平地承载多个视图(EditText、Buttons、CheckBox 等),因此某些视图可能当前在屏幕上不可见。因此,无法对不可见的视图应用matches(isDisplayed()) 。
要测试当前窗口上不可见的视图,请使用withEffectiveVisibility:
// check view exists in current layout hierarchy
onView(withId(R.id.view_id)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
使用 Espresso 测试片段
您的活动(屏幕)可以划分为称为片段的较小容器。在测试期间,您需要先将片段添加到主机活动中,这可以在开始实际测试之前完成,也可以在需要时完成。
@Rule
public ActivityTestRule<NewsActivity> activityTestRule =
new ActivityTestRule<>(NewsActivity.class);
@Before
public void yourSetUPFragment() {
activityTestRule.getActivity()
.getFragmentManager().beginTransaction();
}
此处@Before函数将在开始测试之前执行。它类似于将片段加载到主机活动的设置函数,这在测试仅面向片段时很合适。
此交易也可在稍后需要时进行。
注意:您还可以创建普通片段对象并使用片段事务将它们添加到主机活动。
创建自定义 ViewAction
常见的做法之一是更改TextView中的文本,但在EditText中输入文本的常规方法不能应用于TextView,因此不能使用下面的方法。
onView(withId(R.id.editText)).perform(typeText("my text"), closeSoftKeyboard());
上述操作会失败,因为TextView不支持输入法编辑器 (IME) ,也就是说用户无法通过键盘将值输入到TextView中。要将文本输入到TextView中,需要自定义ViewAction 。
使用自定义 ViewAction 在 TextView 中输入文本
ViewAction是一个抽象类,因此要创建自定义的ViewAction,需要创建一个ViewAction类型的匿名类:
public static ViewAction setTextInTextView(final String value){
return new ViewAction() {
@SuppressWarnings("unchecked")
@Override
public Matcher<View> getConstraints() {
return allOf(isDisplayed(), isAssignableFrom(TextView.class));
// ^^^^^^^^^^^^^^^^^^^
// To check that the found view is TextView or it's subclass like EditText
// so it will work for TextView and it's descendants
}
@Override
public void perform(UiController uiController, View view) {
((TextView) view).setText(value);
}
@Override
public String getDescription() {
return "replace text";
}
};
}
然后它可以应用为:
onView(withId(R.id.textview_id))
.perform(setTextInTextView("text input"));
检查 FontSize 等属性
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~