解决方案

Android单元测试全解

seo靠我 2023-09-23 04:15:00

  自动化测试麻烦吗?说实在,麻烦!有一定的学习成本。但是,自动化测试有以下优点:

节省时间:可以指定测试某一个activity,不需要一个个自己点单元测试:既然Java可以进行单元测试,Android为什SEO靠我么就不可以呢?一键适配:不解释

Android自动化测试框架主要有:Espresso、UI Automator以及Robolectric。滴滴~~ 开车开车!

1、Java单元测试

Android studSEO靠我io(以下简称as)可以跑纯Java代码,这个想必大家都知道。这里就简单介绍一下as如何跑Java代码,作为热身运动吧!

首先打开测试包,在app->src->test目录下,如下图所示,其中AndroSEO靠我idTest包是针对Android工作的测试,先不管他。

这里as为我们创建了一个测试类,直接打开,as中采用Junit4的测试包,主要代码如下。

@RunWith(JUnit4.class) SEO靠我 public class ExampleUnitTest {@Beforepublic void before(){//在测试前的工作}@Afterpublic void after(){// SEO靠我测试完成后的工作}@Testpublic void addition_isCorrect() {//主要工作} }

这就是最简单的Java测试,预热完毕,接下来进入本文的主角

2、AndrSEO靠我oid单元测试——Espresso

AndroidJUnitRunner类是一个JUnit测试运行器,它允许您在Android设备上运行JUnit 3或JUnit 4样式测试类,包括使用EspressoSEO靠我和UI Automator测试框架的测试类。

测试运行器与您的JUnit 3和JUnit 4(高达JUnit 4.10)测试兼容。 但是,您应该避免将JUnit 3和JUnit 4测试代码混合在同一个包SEO靠我中,因为这可能会导致意外的结果。 如果您正在创建一个测试JUnit 4测试类以在设备或模拟器上运行,那么您的测试类必须以@RunWith(AndroidJUnit4.class)注释为前缀。

先看appSEO靠我下的build.gradle依赖:

dependencies {androidTestCompile com.android.support:support-annotations:25.4.0andrSEO靠我oidTestCompile com.android.support.test:runner:1.0.0 androidTestCompile com.android.support.test:rulSEO靠我es:1.0.0 androidTestCompile com.android.support.test.espresso:espresso-core:3.0.2 } SEO靠我android {defaultConfig {testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"} SEO靠我 }

如果依赖冲突,请加入以下代码:

androidTestImplementation(com.android.support.test.espresso:espresso-core:3.SEO靠我0.2, {exclude group: com.android.support, module: support-annotations })

2.1获取application

最常见的SEO靠我应用案例就是,在进行网络测试的时候,如果您的项目很大,编译的时间很长,那么单单为看一个请求结果就要花费相当长的时间,这是不能容忍的,我们可以通过Android的单元测试来模拟请求,如下代码所示。

@RuSEO靠我nWith(AndroidJUnit4.class) public class ExampleInstrumentedTest {@Beforepublic void init() {SEO靠我Context appContext = InstrumentationRegistry.getTargetContext();x.Ext.init((Application) appContext.SEO靠我getApplicationContext());}@Testpublic void useAppContext() {// Context of the app under test.RequestSEO靠我Params requestParams = new RequestParams("https://www.baidu.com/");String str = x.http().getSync(reqSEO靠我uestParams, String.class);System.out.println("\n"+str+"\n");} }

通过InstrumentationRegistry,我们就SEO靠我可以获取到context对象,再通过context就可以获取application对象,之后就可以构建一个网络请求,请注意,在测试方法中,必须使用同步请求,否则测试用例会直接忽略回调方法,直接结束程序SEO靠我,导致无法获取到请求结果。

Android单元测试分为:小型测试、中型测试,大型测试,他们的区别如下。

小型测试(SmallTest):与系统隔离运行,执行时间较短,最长执行时间为200ms中型测试(MeSEO靠我diumTest):集成了多个组件,并可以在模拟器或者真机上运行,最长执行时间为1000ms大型测试(LargeTest):可以运行UI流程的测试工作,确保APP按照预期在仿真器或实际设备上工作。最长SEO靠我执行时间为1000ms

在Android单元测试中可以使用断言来判断变量值是否符合预期,常用的有assertThat、assertEquals、assertNotSame等

2.2获取对应组件

该框架提供ASEO靠我ctivityTestRule来管理被测试的activity,例如MainActivity对应的布局文件如下

<?xml version="1.0" encoding="utf-8"?> SEO靠我 <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/andrSEO靠我oid"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/toolsSEO靠我"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivitySEO靠我"><EditTextandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text=""andSEO靠我roid:id="@+id/main_text"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLSEO靠我eftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"SEO靠我 /></android.support.constraint.ConstraintLayout>

MainActivity的代码这里就不贴出来了,直接看测试代码:

@RunWith(AndroidJUnSEO靠我it4.class) @LargeTest public class MainTest {@Rulepublic ActivityTestRule<MainActiviSEO靠我ty> mActivityRule = new ActivityTestRule<>(MainActivity.class);@Testpublic void Run() {onView(withIdSEO靠我(R.id.main_text)).perform(typeText("Hello MainActivity!"), closeSoftKeyboard());} }

这里简单说明一下:SEO靠我

withId(R.id.main_text):通过ID找到对应的组件,并将其封装成一个MatcheronView():将窗口焦点给某个组件,并返回ViewInteraction实例perform():SEO靠我该组件需要执行的任务,传入ViewAction的实例,可以有多个,意味着用户的多种操作typeText():输入字符串任务,还有replaceText方法也可以实现类似的效果,不过没有输入动画closSEO靠我eSoftKeyboard():关闭软键盘

以上就是最基本的自动化测试代码。点击Run方法边上的运行按钮,直接运行在设备上即可,效果如下所示。

类似的还有点击事件:

onView(withId(R.id.mSEO靠我ain_text)).perform(click());

双击事件:

onView(withId(R.id.main_text)).perform(doubleClick());

判断是否符合预期

onVieSEO靠我w(withId(R.id.main_text)).check(matches(withText("Hello MainActivity!")));

更多请看ViewActions类提供的API

2.3模SEO靠我拟listView的点击事件

以上是针对唯一ID的事件,那么如果有多个组件的ID是一样的呢?例如模拟 listView的item点击事件,是如何区分每一个item呢?先看如何处理多个组件ID相同的情况。SEO靠我

大家知道可以通过ID来查找对应的视图,这里也可以通过显示的文本来查找视图: onView(withText("Hello MainActivity!"));

那么,如果通过ID和显示的文本不就可以定位唯一SEO靠我的视图了吗?如下

onView(allOf(withId(R.id.main_text), withText("Hello MainActivity!")));

或者这样来筛选不匹配的视图

onView(aSEO靠我llOf(withId(R.id.button_signin), not(withText("Sign-out"))));

更多请看ViewMatchers提供的API

接下来看如何模拟listview(SEO靠我GridView和Spinner均适用)的点击事件

我们先创建一个SecondActivity

public class ListActivity extends AppCompatActivity {pSEO靠我rivate ListView listView ;private List<HashMap<String ,String>> data = new ArrayList<>();public statSEO靠我ic final String KEY = "key";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreSEO靠我ate(savedInstanceState);setContentView(R.layout.activity_second);listView = findViewById(R.id.list_vSEO靠我iew);initDate();listView.setAdapter(new SimpleAdapter(this,data,R.layout.item_list,new String[]{KEY}SEO靠我,new int[]{R.id.item_list_text}));listView.setOnItemClickListener(new AdapterView.OnItemClickListeneSEO靠我r() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {ToasSEO靠我t.makeText(ListActivity.this,data.get(position).get(KEY),Toast.LENGTH_LONG).show();}});}private voidSEO靠我 initDate() {for(int i =0 ;i < 90 ;i++){HashMap<String,String> map = new HashMap<>();map.put(KEY,"第"SEO靠我+(1+i)+"列");data.add(map);}} }

  对应的布局文件就是一个listView,item对应的布局是一个textView,这里就不贴出来了,主要看测试类:

@RunWSEO靠我ith(AndroidJUnit4.class) @LargeTest public class ListViewTest {private static final SEO靠我String TAG = "ListViewTest ";@Rulepublic ActivityTestRule<ListActivity> mActivityRule = new ActivitySEO靠我TestRule<>(ListActivity.class);@Beforepublic void init() {mActivityRule.getActivity();}@Testpublic vSEO靠我oid Run() {onData(allOf(is(instanceOf(Map.class)),hasEntry(equalTo(ListActivity.KEY), is("第10列")))).SEO靠我perform(click());} }

  这里选择数据为第10行的item,并执行点击动作,这里着重讲一下hasEntry() 这个方法,该方法需要传两个Matcher,也就是map的键SEO靠我名和对应的值。通过map的键、值来唯一确定一个item,拿到对应的item就可以类似于视图一样去执行动作了,效果如下。

动画比较快,但是可以看到listview先是滚到第10行,然后才执行点击事件,这是SEO靠我因为Espresso负责滚动目标元素,并将元素放在焦点上。

  有同学马上就提出了,recycleView才是主流,用listview的很少了~~,没事,我们来看如何进行recycleView的自动化测试

2SEO靠我.4模拟recycleView点击事件

对recyclerView进行自动化测试需要再添加以下依赖,注意,是在之前的依赖基础上添加以下代码。

androidTestCompile com.android.SEO靠我support.test.espresso:espresso-contrib:3.0.0 androidTestCompile com.android.support:recyclerSEO靠我view-v7:25.4.0

我们创建一个RecyclerActivity,内容如下:

public class RecyclerActivity extends AppCompatActivity {pSEO靠我rivate RecyclerView recyclerView;private RecyclerAdapter<String> adapter;@Overrideprotected void onCSEO靠我reate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activitSEO靠我y_recycler);recyclerView = findViewById(R.id.recycler_view);recyclerView.setLayoutManager(new LinearSEO靠我LayoutManager(this));adapter = new RecyclerAdapter<>(this, R.layout.item_list);recyclerView.setAdaptSEO靠我er(adapter);List<String> list = new ArrayList<>();for(int i =0 ;i < 50 ;i++){list.add("第"+(1+i)+"列")SEO靠我;}adapter.setData(list);} }

对应的布局文件就是一个recyclerview,item的布局只有一个textView,这里也就不贴出来了,adapter也很简单SEO靠我,给textView一个点击事件,如下:

public class RecyclerAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHoSEO靠我lder> {private List<T> data = new ArrayList<>();private Context context ;private int layout;public RSEO靠我ecyclerAdapter(Context context, int layout) {this.context = context;this.layout = layout;}public voiSEO靠我d setData(List<T> data) {this.data.clear();this.data.addAll(data);notifyDataSetChanged();}@OverridepSEO靠我ublic RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {return new Holder(SEO靠我LayoutInflater.from(context).inflate(layout,null,false));}@Overridepublic void onBindViewHolder(RecySEO靠我clerView.ViewHolder holder, final int position) {Holder holder1 = (Holder) holder;holder1.textView.sSEO靠我etText(data.get(position).toString());holder1.itemView.setOnClickListener(new View.OnClickListener()SEO靠我 {@Overridepublic void onClick(View v) {Toast.makeText(context,data.get(position).toString(),Toast.LSEO靠我ENGTH_LONG).show();}});}@Overridepublic int getItemCount() {return data.size();}private class HolderSEO靠我 extends RecyclerView.ViewHolder{TextView textView ;public Holder(View itemView) {super(itemView);teSEO靠我xtView = itemView.findViewById(R.id.item_list_text);}} }

接下来看测试类:

@RunWith(AndroidJUnit4.classSEO靠我) @LargeTest public class RecycleViewTest {private static final String TAG = "ExamplSEO靠我eInstrumentedTest";@Rulepublic ActivityTestRule<RecyclerActivity> mActivityRule = new ActivityTestRuSEO靠我le<>(RecyclerActivity.class);@Testpublic void Run() {onView(ViewMatchers.withId(R.id.recycler_view))SEO靠我.perform(RecyclerViewActions.actionOnItemAtPosition(10, click()));} }

在run方法中我们可以看到基本与之前的类似,不SEO靠我同的是需要通过RecyclerViewActions类提供的API来执行任务,其中actionOnItemAtPosition的第一个参数是recycleview的item位置,第二个参数是对应的动作SEO靠我,效果与listView的一致,这里就不贴了。

这里可以看出,recycleview的测试类要优于listView,listView通过item的值来查找对应的item,而recycleview直接通过SEO靠我位置来查找

2.5 模拟用户点击actionbar

新建一个MenuActivity,主要代码如下

public class MenuActivity extends AppCompatActivity {SEO靠我@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setCSEO靠我ontentView(R.layout.activity_menu);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuISEO靠我nflater().inflate(R.menu.menu_test, menu);return super.onCreateOptionsMenu(menu);}@Overridepublic boSEO靠我olean onOptionsItemSelected(MenuItem item) {Toast.makeText(this,item.getTitle(),Toast.LENGTH_SHORT).SEO靠我show();return super.onOptionsItemSelected(item);} }

menu布局代码如下:

<?xml version="1.0" encoding="SEO靠我utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:android1="httSEO靠我p://schemas.android.com/apk/res-auto"><itemandroid:id="@+id/nav_1"android:title="item1"android1:showSEO靠我AsAction="never" /><itemandroid:id="@+id/nav_2"android:title="item2"android1:showAsAction="never" />SEO靠我 </menu>

测试代码如下:

@RunWith(AndroidJUnit4.class) @LargeTest public class MenuTesSEO靠我t {@Rulepublic ActivityTestRule<MenuActivity> mActivityRule = new ActivityTestRule<>(MenuActivity.clSEO靠我ass);@Testpublic void test(){//打开menuopenContextualActionModeOverflowMenu();//模拟点击item2onView(withTeSEO靠我xt("item2")).perform(click());} }

效果如下:

如果您在测试中遇到MainLooper还没有调用prepare异常

java.lang.RuntimeExceSEO靠我ption: Cant create handler inside thread that has not called Looper.prepare() at android.os.SEO靠我Handler.<init>(Handler.java:200) at android.os.Handler.<init>(Handler.java:114) at aSEO靠我ndroid.widget.Toast$TN.<init>(Toast.java:344) at android.widget.Toast.<init>(Toast.java:100)SEO靠我

可以加上以下代码解决该问题

@Testpublic void test() {getInstrumentation().runOnMainSync(new Runnable() {@OverridepuSEO靠我blic void run() {//test content}});}

3、Android单元测试——Robolectric

如果您的应用的测试环境需要单元测试与Android框架进行更广泛的交互,则可SEO靠我以使用Robolectric。 该工具可让您在工作站上或常规JVM中的持续集成环境中运行测试,而无需仿真器,几乎与Android设备运行测试的完全保真度相匹配,但仍比执行设备测试更快,支持AndroiSEO靠我d平台的以下几个方面。

Android4.1以及更高Android Gradle 插件2.4以及更高组件生命周期事件循环所有资源:SDK, Resources, Native Method

grade配置SEO靠我

testImplementation "org.robolectric:robolectric:3.8" testImplementation "org.assertj:assertSEO靠我j-core:1.7.0" // robolectric对应的support-v4包 testImplementation org.robolectric:shadowSEO靠我s-support-v4:3.0android {testOptions {unitTests {includeAndroidResources = true}} }

基本用法如下所示。SEO靠我

@RunWith(RobolectricTestRunner.class) public class MyActivityTest {@Testpublic void clickingSEO靠我Button_shouldChangeResultsViewText() throws Exception {MyActivity activity = Robolectric.setupActiviSEO靠我ty(MyActivity.class);Button button = (Button) activity.findViewById(R.id.button);TextView results = SEO靠我(TextView) activity.findViewById(R.id.results);button.performClick();assertThat(results.getText().toSEO靠我String()).isEqualTo("Robolectric Rocks!");} }

Robolectric社区已经有详细的说明,这里就不再赘述

如有疑问,可以参考文末的demo,需SEO靠我要注意的是Robolectric的相关测试是在test目录下,可以mock出Android环境。

4、Android测试——UI Automator

先配置依赖

dependencies {androidTSEO靠我estCompile com.android.support:support-annotations:25.4.0androidTestCompile com.android.support.testSEO靠我:runner:1.0.0 androidTestImplementation com.android.support.test.uiautomator:uiautomator-v18:2.1.3anSEO靠我droidTestCompile org.hamcrest:hamcrest-integration:1.3}

注意,UI Automator最低支持Android 4.3 (API level 18)SEO靠我

在MainActivity中有四个组件editText、textView和button,布局就不贴出来了,在MainActivity的Java代码中主要是点击方法中,如下:

@OverridepubliSEO靠我c void onClick(View view) {// Get the text from the EditText view.final String text = mEditText.getTSEO靠我ext().toString();final int changeTextBtId = R.id.changeTextBt;final int activityChangeTextBtnId = R.SEO靠我id.activityChangeTextBtn;if (view.getId() == changeTextBtId) {//将edit中的text内容显示到textView中mTextView.sSEO靠我etText(text);} else if (view.getId() == activityChangeTextBtnId) {//启动新的activity,并将text传给新的activity显SEO靠我示Intent intent = ShowTextActivity.newStartIntent(this, text);startActivity(intent);}}

主要看测试代码,这里创建一个CSEO靠我hangeTextBehaviorTest测试类:

@RunWith(AndroidJUnit4.class) @SdkSuppress(minSdkVersion = 18) SEO靠我 public class ChangeTextBehaviorTest {private static final String BASIC_SAMPLE_PACKAGE= "com.examSEO靠我ple.android.testing.uiautomator.BasicSample";private static final int LAUNCH_TIMEOUT = 5000;private SEO靠我static final String STRING_TO_BE_TYPED = "UiAutomator";private UiDevice mDevice;@Beforepublic void sSEO靠我tartMainActivityFromHomeScreen() {// 获取UiDevice的实例mDevice = UiDevice.getInstance(InstrumentationRegiSEO靠我stry.getInstrumentation());// 模拟用户点击home键mDevice.pressHome();//获取要加载的包名final String launcherPackage SEO靠我= getLauncherPackageName();//判断是否为空assertThat(launcherPackage, notNullValue());//等待目标包 的信息mDevice.waSEO靠我it(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT);// 启动目标activity,也就是MainActivitSEO靠我yContext context = InstrumentationRegistry.getContext();final Intent intent = context.getPackageManaSEO靠我ger().getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE);intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASSEO靠我K); // Clear out any previous instancescontext.startActivity(intent);// Wait for the app to appearmDSEO靠我evice.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)), LAUNCH_TIMEOUT);}@Testpublic voidSEO靠我 testChangeText_sameActivity() {//将 STRING_TO_BE_TYPED 内容填充到edittext中mDevice.findObject(By.res(BASICSEO靠我_SAMPLE_PACKAGE, "editTextUserInput")).setText(STRING_TO_BE_TYPED);//给ID为changeTextBt 的组件模拟用户的点击事件mDSEO靠我evice.findObject(By.res(BASIC_SAMPLE_PACKAGE, "changeTextBt")).click();// 等待获取MainActivity中ID为textToSEO靠我BeChanged的textView的内容,等待时间为500msUiObject2 changedText = mDevice.wait(Until.findObject(By.res(BASIC_SSEO靠我AMPLE_PACKAGE, "textToBeChanged")),500 /* wait 500ms */);//判断是否正确assertThat(changedText.getText(), iSEO靠我s(equalTo(STRING_TO_BE_TYPED)));}@Testpublic void testChangeText_newActivity() {// 同上mDevice.findObjSEO靠我ect(By.res(BASIC_SAMPLE_PACKAGE, "editTextUserInput")).setText(STRING_TO_BE_TYPED);mDevice.findObjecSEO靠我t(By.res(BASIC_SAMPLE_PACKAGE, "activityChangeTextBtn")).click();// Verify the test is displayed in SEO靠我the UiUiObject2 changedText = mDevice.wait(Until.findObject(By.res(BASIC_SAMPLE_PACKAGE, "show_text_SEO靠我view")),500 /* wait 500ms */);assertThat(changedText.getText(), is(equalTo(STRING_TO_BE_TYPED)));}/*SEO靠我** 获取包名*/private String getLauncherPackageName() {// Create launcher Intentfinal Intent intent = newSEO靠我 Intent(Intent.ACTION_MAIN);intent.addCategory(Intent.CATEGORY_HOME);// Use PackageManager to get thSEO靠我e launcher package namePackageManager pm = InstrumentationRegistry.getContext().getPackageManager();SEO靠我ResolveInfo resolveInfo = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);return resolSEO靠我veInfo.activityInfo.packageName;} }

该框架的逻辑是模拟用户在使用APP的过程,这个测试用例的主要流程是:用户在桌面点击目标APP,进去,输入字符串,用SEO靠我户点击activityChangeTextBtn组件,跳转到ShowTextActivity,并传入内容,让其显示出来。然后点击changeTextBt组件,显示用户输入内容;

效果如下

该测试类有三个方SEO靠我法,其中在测试前需要获取 UiDevice的实例,步骤如下:

通过调用getInstance()方法并将Instrumentation对象作为参数传递,获取UiDevice对象以访问要测试的设备。通过调SEO靠我用UiDevice实例的findObject()方法,获取UiObject对象以访问设备上显示的UI组件(例如,前景中的当前视图)。可以通过调用UiObject方法模拟要在该UI组件上执行的特定用户交SEO靠我互;例如,调用performMultiPointerGesture()来模拟多点触摸手势,调用setText()来编辑文本字段。在执行这些用户交互之后,检查UI是否反映了预期的状态或行为。

显然该框架需SEO靠我要从MainActivity开始,整个的模拟用户使用过程,好处是不会绑定特定的activity,资源具有全局性。源码见GitHub

当然,也可以通过以下的方式拿到对应的组件:

UiObject okButSEO靠我ton = mDevice.findObject(new UiSelector().text("OK").className("android.widget.Button"));// SimulateSEO靠我 a user-click on the OK button, if found. if(okButton.exists() && okButton.isEnabled()) {okBSEO靠我utton.click(); }

如果要访问应用程序中的特定UI组件,请使用UiSelector类。 此类表示当前显示的UI中特定元素的查询。

如果找到多个匹配元素,则布局层次结构中的第一SEO靠我个匹配元素将作为目标UiObject返回。 构建UiSelector时,可以将多个属性链接在一起以优化搜索。 如果未找到匹配的UI元素,则抛出UiAutomatorObjectNotFoundExceSEO靠我ption。

我们可以使用childSelector()方法嵌套多个UiSelector实例。 例如,以下代码示例显示了测试如何指定搜索以在当前显示的UI中查找第一个ListView,然后在该ListVSEO靠我iew中搜索以查找具有文本属性Apps的UI元素UiObject appItem = new UiObject(new UiSelector().className("android.widget.LSEO靠我istView").instance(0).childSelector(new UiSelector().text("Apps")));

一旦您的测试获得了UiObject对象,您就可以调用UiObjeSEO靠我ct类中的方法来对该对象所表示的UI组件执行用户交互。您可以指定以下操作:

click():单击UI元素可见边界的中心。dragTo():将此对象拖动到任意坐标。setText():在清除字段内容后,在SEO靠我可编辑字段中设置文本。相反,clearTextField()方法清除可编辑字段中的现有文本。swipeUp():对UiObject执行向上滑动操作。类似地,swipeDown(),swipeLeft(SEO靠我)和swipeRight()方法执行相应的操作。

如果测试FrameLayout内容,则需要构建UiCollection,例如以下代码:

UiCollection videos = new UiColleSEO靠我ction(new UiSelector().className("android.widget.FrameLayout"));// 检索此集合中的视频数量 int count = vSEO靠我ideos.getChildCount(new UiSelector().className("android.widget.LinearLayout"));// 查找特定视频并模拟用户单击它 SEO靠我 UiObject video = videos.getChildByText(new UiSelector().className("android.widget.LinearLayout"SEO靠我), "Cute Baby Laughing"); video.click();// 模拟选择与视频关联的复选框 UiObject checkBox = video.gSEO靠我etChild(new UiSelector().className("android.widget.Checkbox")); if(!checkBox.isSelected()) cSEO靠我heckbox.click();

对于可滑动视图,可以使用UiScrollable类模拟显示屏上的垂直或水平滚动。 当UI元素位于屏幕外并且您需要滚动以将其置于视图中时,此技术很有用。

以下代码段显示了如SEO靠我何模拟向下滚动“设置”菜单并单击“关于”平板电脑选项UiScrollable settingsItem = new UiScrollable(new UiSelector().className("aSEO靠我ndroid.widget.ListView")); UiObject about = settingsItem.getChildByText(new UiSelector().claSEO靠我ssName("android.widget.LinearLayout"), "About tablet"); about.click();

5、总结

话不多说,~~附上 代码链接

“SEO靠我”的新闻页面文章、图片、音频、视频等稿件均为自媒体人、第三方机构发布或转载。如稿件涉及版权等问题,请与 我们联系删除或处理,客服邮箱:html5sh@163.com,稿件内容仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同 其观点或证实其内容的真实性。

网站备案号:浙ICP备17034767号-2