谷歌 2013 年的时候开源了 espress,谷歌的思路是,等到它足够成熟和稳定以后,将其迁移到 Android SDK 中,以此可见对他的重视。Google 使用 Espresso 测试了他们自己的超过 30 个应用程序,包括 G+、Maps 和 Drive。
Espresso 测试是非常容易实现的,由三步构成:
先看下官方给的示例,就能理解以上的三个步骤:
- onView(withId(R.id.my_view)) // withId(R.id.my_view) is a ViewMatcher
- .perform(click()) // click() is a ViewAction
- .check(matches(isDisplayed())); // matches(isDisplayed()) is a ViewAssertion
Espresso 框架是 google 官方大力推荐的一套测试框架, 所以无论如何都要学习一下的. 另外, 自 Android Studio2.2 版本开始, google 就为 Espresso 框架内置了一个图形化界面, 用来自动生成单元测试代码。
接下来一起写一 demo 测试,深入了解 Espresso。
支持 Espresso:
- dependencies {
- ...
- testCompile 'junit:junit:4.12'
- androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2', {
- exclude group: 'com.android.support', module: 'support-annotations'
- }
- }
在 dependencies 中添加,一般默认会有 testCompile 'junit:junit:4.12',所以我们只需添加另一句即可。
- defaultConfig{
- ...
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- }
在 defaultConfig 中添加如上语句,支持测试运行。
特别注意,该类应在 androidTest 文件夹下
举个简单例子:
- @RunWith(AndroidJUnit4.class)
- @LargeTest
- public class MainActivityInstrumentationTest {
- @Rule
- public ActivityTestRule mActivityRule = new ActivityTestRule<>(
- MainActivity.class);
- @Test
- public void sayHello(){
- onView(withText("Say hello!")).perform(click());
- onView(withId(R.id.textView)).check(matches(withText("Hello, World!")));
- }
- }
- @Rule
- public ActivityTestRule mTestRule = new ActivityTestRule<>(MainActivity.class);
这句话就定义了一个测试规则,可以看到构造方法的参数里指定了一个 MainActivity.class, 具体的体现就是当你运行这段测试代码时,app 将会直接打开 MainActivity 界面然后进行你所定义的测试用例。 所以当你想直接测试某个界面时,你可以把那个界面填到这个参数里, 这样就直接打开你指定的界面进行测试了。
- @Test
- public void testLogin() {
- ...
- }
定义一个测试方法,当你的测试类运行时,所执行的代码就是 Test 注解下的方法 (Espresso 还提供了其他的一些注解: 比如 @After,@Before 等,具体的用法可以去我上面写的 android 官网上查看),当然上面那段代码对应的就是 testLogin 测试方法,testLogin 方法里所定义的就是要测试的内容。
使用 onView 方法找到 view:其中参数可以是 withId(通过资源 id 查找),withText(通过显示内容查找)有多个约束条件时,可以使用 allOf 如 allOf(withText("Hello") ,withId(R.id.hello))
注意:
对 View 的操作:perform() 方法 方式是 onView(...).perform()。也可以执行多个操作在一个 perform 中如:perform(click(),clearText())。
所有的操作都有一个前提 ———— 就是要执行的 view 必须在当前界面上显示出来(有且可见)。
方法名 | 含义 |
---|---|
click() | 点击 view |
clearText() | 清除文本内容 |
swipeLeft() | 从右往左滑 |
swipeRight() | 从左往右滑 |
swipeDown() | 从上往下滑 |
swipeUp() | 从下往上滑 |
click() | 点击 view |
closeSoftKeyboard() | 关闭软键盘 |
pressBack() | 按下物理返回键 |
doubleClick() | 双击 |
longClick() | 长按 |
scrollTo() | 滚动 |
replaceText() | 替换文本 |
openLinkWithText() | 打开指定超链 |
使用 check() 方法来检查 View 是否符合我们的期望: onView(...).check() 检查 view 中是否含有文本"hello"check(matches(withText("hello")))
我们基本所有的 app 都有登录功能,都需要呼入用户名和密码,那么在点击登录之前需要对用户名和密码进行非空、格式等验证。
以下示例我们点击登录按钮时,首先对输入的用户名和密码进行验证,验证不通过在 TextView 上显示对应原因,验证没有问题显示 "登录成功"。
- @Override public void onClick(View view) {
- if (view.getId() == R.id.bt_login) {
- login();
- }
- }
- /**
- * 去登录
- */
- private void login() {
- String name = et_name.getText().toString().trim();
- String pwd = et_pwd.getText().toString().trim();
- if (TextUtils.isEmpty(name)) {
- tv_login_result.setText("用户名为空");
- return;
- }
- if (name.length() < 6) {
- tv_login_result.setText("用户名格式错误");
- return;
- }
- if (TextUtils.isEmpty(pwd)) {
- tv_login_result.setText("密码为空");
- return;
- }
- if (pwd.length() < 6) {
- tv_login_result.setText("密码格式错误");
- return;
- }
- tv_login_result.setText("登录成功");
- }
其他代码忽略。
- @RunWith(AndroidJUnit4.class)@LargeTest public class MainActivityTest {
- private String[] names = {
- "",
- "a",
- "123123"
- };
- private String[] pwds = {
- "",
- "a",
- "123123"
- };
- @Rule public ActivityTestRule mTestRule = new ActivityTestRule < >(MainActivity.class);
- @Before public void init() {
- Log.e("TAG", "init: ");
- }
- @Test public void testLogin() {
- // 不做任何输入,直接点击登录
- onView(allOf(withId(R.id.bt_login), isDisplayed())).perform(click());
- onView(allOf(withId(R.id.tv_login_result), isDisplayed())).check(matches(withText("用户名为空")));
- // 用户名是空,点击登录
- onView(allOf(withId(R.id.et_name), isDisplayed())).perform(replaceText(names[0]), closeSoftKeyboard());
- onView(allOf(withId(R.id.bt_login), isDisplayed())).perform(click());
- onView(allOf(withId(R.id.tv_login_result), isDisplayed())).check(matches(withText("用户名为空")));
- // 用户名格式错误,点击登录
- onView(allOf(withId(R.id.et_name), isDisplayed())).perform(replaceText(names[1]), closeSoftKeyboard());
- onView(allOf(withId(R.id.bt_login), isDisplayed())).perform(click());
- onView(allOf(withId(R.id.tv_login_result), isDisplayed())).check(matches(withText("用户名格式错误")));
- // 用户名和密码都正确,点击登录
- onView(allOf(withId(R.id.et_name), isDisplayed())).perform(replaceText(names[2]), closeSoftKeyboard());
- onView(allOf(withId(R.id.et_pwd), isDisplayed())).perform(replaceText(pwds[2]), closeSoftKeyboard());
- onView(allOf(withId(R.id.bt_login), isDisplayed())).perform(click());
- onView(allOf(withId(R.id.tv_login_result), isDisplayed())).check(matches(withText("登录成功")));
- }
- }
这里我们事先定义了一些测试数据,使用 Espresso 进行模拟各种情况输入和点击,测试是否符合我们的预期:
对 Espresso 的介绍大概就是这些了,希望大家多提建议,一起进步。
来源: https://juejin.im/post/5a30e0996fb9a045211eb341