本文共 9380 字,大约阅读时间需要 31 分钟。
前2篇我们已经详细介绍了espresso的架构以及相应的API,相信大家也有了一定的了解,理论讲的再多,还是不如手上自己敲一遍代码。
还是深入浅出系列的套路,让我这个小司机带大家一步一步进入espresso的世界吧。github
github,如果你还用svn的话,请放弃阅读本系列文章,太low了,而且本系列的code都是采用google官方的espresso的demo,都来源于github。android studio android studio,这个不用说,目前android开发者最好的工具,并且他有很多帮助espresso测试的插件或功能,比如录制功能等。android sdk android sdk,这个更不用说,如果你连这个都没,还学什么android。genymotion genymotion,android目前来说最好的模拟器,虽然原生的也很不错,但是开发者首先得还是genymotion最好你已经拥有了项目源码,espresso并不是单纯的黑盒ui测试工具,它能干得事情很多,包括单元测试,集成测试,甚至在mock服务,以及将你需要的内容注入到代码中,所以我把称为灰盒工具。
如果之前没有做个android项目的话,也可以在github上找一些开源的android app 练手。不过建议大家从espresso demo库入手。android_studio
如上图,我们可以创建新的项目,导入已经存在android项目,从版本管理软件中导入,从gradle等其他工具中导入,以及获取android代码样例导入。
google android 所有的测试demo都在以下github地址 下载完成后,我们进入espresso目录,可以看到espresso的demo还是很丰富的。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # lqi @ CNlqi-3 in ~/work/test/android/android-testing on git:master x [0:19:24] $ cd ui/espresso # lqi @ CNlqi-3 in ~/work/test/android/android-testing/ui/espresso on git:master x [0:19:31] $ ls BasicSample CustomMatcherSample EspressoSpoonDemo IntentsAdvancedSample MultiWindowSample WebBasicSample BasicSampleBundled DataAdapterSample IdlingResourceSample IntentsBasicSample RecyclerViewSample spoon-gradle-plugin # lqi @ CNlqi-3 in ~/work/test/android/android-testing/ui/espresso on git:master x [0:19:37] $ cd BasicSample # lqi @ CNlqi-3 in ~/work/test/android/android-testing/ui/espresso/BasicSample on git:master x [0:19:40] $ pwd /Users/lqi/work/test/android/android-testing/ui/espresso/BasicSample # lqi @ CNlqi-3 in ~/work/test/android/android-testing/ui/espresso/BasicSample on git:master x [0:20:42] $ |
选择BasicSample
导入或者直接命令行studio .
打开该项目。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.1.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { jcenter() } } ext { buildToolsVersion = "24.0.1" supportLibVersion = "24.2.0" runnerVersion = "0.5" rulesVersion = "0.5" espressoVersion = "2.2.2" } |
app目录为项目主目录包含项目源代码以及测试代码
app里面也包含build.gradle文件,有时候项目可能包含几个主目录,那么各个目录的下的build.gradle文件都继承自顶层的build.gradle文件。 app下的build.gradle文件配置了android的配置信息,以及会用到的依赖。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | apply plugin: 'com.android.application' android { compileSdkVersion 24 buildToolsVersion rootProject.buildToolsVersion defaultConfig { applicationId "com.example.android.testing.espresso.BasicSample" minSdkVersion 10 targetSdkVersion 24 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } lintOptions { abortOnError false } productFlavors { } } dependencies { // App dependencies compile 'com.android.support:support-annotations:' + rootProject.supportLibVersion; compile 'com.google.guava:guava:18.0' // Testing-only dependencies // Force usage of support annotations in the test app, since it is internally used by the runner module. androidTestCompile 'com.android.support:support-annotations:' + rootProject.supportLibVersion; androidTestCompile 'com.android.support.test:runner:' + rootProject.runnerVersion; androidTestCompile 'com.android.support.test:rules:' + rootProject.rulesVersion; androidTestCompile 'com.android.support.test.espresso:espresso-core:' + rootProject.espressoVersion; } |
BasicSample APP就长样子。
启动espresso首先启动android emulator/genymotion,之后直接点击run按钮就能部署app到模拟器上。
log如下.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | Testing started at 2:32 PM ... 12/09 14:32:04: Launching ChangeTextBehaviorTe... $ adb push /Users/lqi/work/test/android/android-testing/ui/espresso/BasicSample/app/build/outputs/apk/app-debug.apk /data/local/tmp/com.example.android.testing.espresso.BasicSample $ adb shell pm install -r "/data/local/tmp/com.example.android.testing.espresso.BasicSample" pkg: /data/local/tmp/com.example.android.testing.espresso.BasicSample Success $ adb push /Users/lqi/work/test/android/android-testing/ui/espresso/BasicSample/app/build/outputs/apk/app-debug-androidTest-unaligned.apk /data/local/tmp/com.example.android.testing.espresso.BasicSample.test $ adb shell pm install -r "/data/local/tmp/com.example.android.testing.espresso.BasicSample.test" pkg: /data/local/tmp/com.example.android.testing.espresso.BasicSample.test Success Running tests $ adb shell am instrument -w -r -e debug false -e class com.example.android.testing.espresso.BasicSample.ChangeTextBehaviorTest com.example.android.testing.espresso.BasicSample.test/android.support.test.runner.AndroidJUnitRunner Client not ready yet.. Started running tests Tests ran to completion. |
此实例BasicSample包含1个textView,1个EditText和2个button,当点击change text 按钮时,会将edittext的值填入textview中。当点击open activity and change text 按钮时,将打开一个新的页面(姑且叫这样吧)并将edittext内容显示在这个页面。
@RunWith(AndroidJUnit4.class)
采用了JUnit 4风格进行编写 ChangeTextBehaviorTest
1 2 | public class ChangeTextBehaviorTest { } |
1 2 3 | @Rule public ActivityTestRule |
1 2 3 4 5 6 7 8 9 10 | @Test public void changeText_sameActivity() { // Type text and then press the button. onView(withId(R.id.editTextUserInput)) .perform(typeText(STRING_TO_BE_TYPED), closeSoftKeyboard()); onView(withId(R.id.changeTextBt)).perform(click()); // Check that the text was changed. onView(withId(R.id.textToBeChanged)).check(matches(withText(STRING_TO_BE_TYPED))); } |
顺便说说其他junit4注解的用法
@Before: 标识在运行测试方法之前运行的代码。可以支持同一个Class中有多个@Before,但是这些方法的执行顺序是随机的。该注解替代了JUnit 3中的setUp()方法。@After: 标识在运行测试方法结束之后运行的代码。可以在其中做一些释放资源的操作。该注解替代了JUnit 3中的tearDown()方法。@BeforeClass: 为测试类标识一个static方法,在测试之前只执行一次。@AfterClass: 为测试类标识一个static方法,在所有测试方法结束之后只执行一次。@Test(timeout=): 为测试方法设定超时时间。
到了这里我们要说下怎么定位所需的元素,其实和web差不多,我们可以利用layout inspector与android device monitor工具。
android_device_monitorandroid_device_monitor 在写一个测试,在editTextUserInput输入‘Espresso’,之后关闭键盘。点击activityChangeTextBtn按钮,查看show_text_view的值是否为‘Espresso’。1 2 3 4 5 6 7 8 9 10 | @Test public void changeText_newActivity() { // Type text and then press the button. onView(withId(R.id.editTextUserInput)).perform(typeText(STRING_TO_BE_TYPED), closeSoftKeyboard()); onView(withId(R.id.activityChangeTextBtn)).perform(click()); // This view is in a different Activity, no need to tell Espresso. onView(withId(R.id.show_text_view)).check(matches(withText(STRING_TO_BE_TYPED))); } |
以上是espresso最常见的测试,希望大家能够好好理解。
AdapterView 是一个从适配器中动态加载数据的特殊控件。最常见的 AdapterView 是 ListView。与像 LinearLayout 这样的静态控件相反,在当前视图结构中,可能只加载了 AdapterView 子控件的一部分, 简单的 onview() 可能会找不到当前没有被加载的视图。Espresso 通过提供单独的 onData()方法来切入点处理此问题,它可以在操作适配器中有该问题的条目或该条目的子项之前将其加载(使其获取焦点)。
导入espresso demo中的MultiWindowSample项目 该测试是从ArrayAdapter类型的dropdown_item控件中选出需要的值,类似我们用搜索引擎时,显示的list。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @Test public void autoCompleteTextView_onDataClickAndCheck() { // NB: The autocompletion box is implemented with a ListView, so the preferred way // to interact with it is onData(). We can use inRoot here too! onView(withId(R.id.auto_complete_text_view)) .perform(typeText("S"), closeSoftKeyboard()); // This is useful because some of the completions may not be part of the View Hierarchy // unless you scroll around the list. onData(allOf(instanceOf(String.class), is("Baltic Sea"))) .inRoot(withDecorView(not(is(mActivity.getWindow().getDecorView())))) .perform(click()); // The text should be filled in. onView(withId(R.id.auto_complete_text_view)) .check(matches(withText("Baltic Sea"))); } |
,AutoCompleteText的选择等。 这些测试项都有一个共同的特点。即不在主UI布局的结构(layout,及其include的layout)之中,是不能直接定位的。 所以这里就需要使用inRoot( ) 了。
onData(allOf(instanceOf(String.class), is("Baltic Sea"))) .inRoot(withDecorView(not(is(mActivity.getWindow().getDecorView())))) .perform(click());
以上代码就解决了之前UiAutomator不支持Toast的验证的问题。 运行测试的方法很多,第一种命令行执行。
切换到当前项目目录,终端运行./gradlew cAT
其中,cAT意为connectedAndroidTest。 另一种方式是在android studio中,点击run按钮,或者右键执行单一测试。
android_device_monitor这一章还是以基础的实践为主,之后我们将深入架构,来看看espresso的API 方法,帮助大家理解API 更好更快的编写测试。
最新内容请见作者的GitHub页:http://qaseven.github.io/
转载地址:http://lnrel.baihongyu.com/