Android Espresso
在本教程中,我们将讨论用于测试Android应用程序UI的Espresso测试框架。
我们将创建一个基本的登录应用程序,并进行一些Espresso测试。
Android Espresso
之前我们已经讨论过Android单元测试。
测试是制造任何产品的重要领域。
它可以帮助我们:
检测我们的代码未涵盖的错误/案例。
尽量减少手动用户测试。
无需一次又一次地测试较早的功能。构建涵盖最终案例的强大应用程序。
Android中的测试主要涉及两种类型:
- 单元测试
- 仪器测试
Espresso测试属于第二种类型。
它通过编写简短的Android UI测试来进行自动化的UI测试。
让我们看一下Espresso工具测试框架的组成部分。
ViewMatchers,ViewActions,ViewAssertions
ViewMatchers –允许我们在视图层次结构中查找视图。
ViewActions –允许我们对视图执行自动操作。
例如点击次数等ViewAssertions –允许我们声明视图的状态。
浓咖啡测试的基本框架代码是:
onView(ViewMatcher) .perform(ViewAction) .check(ViewAssertion)
在onView内部,我们寻找View的ID。
可以使用以下方法来完成:
withId()–传递唯一的ID- withText()-传递视图的文本。
它搜索具有指定文本的视图。
在" perform"内部,我们传递要在View上完成的操作。
例:
click()–单击在onView中传递的视图。
typeText()–传递要在View中输入的字符串。
特别是在EditText中使用。replaceText()–用传递的字符串替换当前文本。closeSoftKeyboard()–关闭键盘。
在check内部,我们主要使用以下方法来声明状态:
matchesdoesNotExist
我们也可以使用Espresso测试来测试视图层次。
例如,我们可以通过以下方式定位视图断言:
onView(withId(R.id.textView)).check(isRightOf(withText("Hello World")));
onView(withId(R.id.textView)).check(isBelow(withText("Hello World")));
位置声明的其他方法有:
isLeftAlignedWith isAbove isTopAlignedWith
Hamcrest Matchers是非常强大的Matchers。
以下示例显示:
onView(withText(startsWith("Hello"))).perform(click());
onView(allOf(withId(R.id.textView),isDisplayed()));
onView(allOf(withId(R.id.textView),hasLinks()));
最后一个检查整个TextView是否为链接。
在以下部分中,我们将创建一个android应用程序并编写我们的第一个意式浓缩咖啡测试。
我们的Android应用程序将包含一个基本的登录表单,其中包含用户名,电话号码和确认号码字段。
按下登录按钮后,如果电话号码字段不匹配,我们将显示一条Toast消息。
如果一切正常,我们将通过Hello向用户推荐。
Espresso测试入门
在build.gradle文件中添加以下依赖项:
androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test:rules:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
在defaultConfig块中添加以下内容:
android{
...
defaultConfig{
...
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
...
}
AndroidJUnitRunner是工具运行器。
这是运行Android测试的切入点。
以下是我们应用的" build.gradle"文件的外观:
确保在运行Espresso测试之前禁用Android设备中的"动画"。
否则,默认的屏幕动画可能会干扰测试。
您可以从"开发人员选项"中禁用它们
代码
下面给出了" activity_main.xml"布局的代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_margin="8dp"
android:orientation="vertical"
tools:context=".MainActivity">
<EditText
android:id="@+id/inUsername"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Username"
<EditText
android:id="@+id/inNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Number"
android:inputType="number"
<EditText
android:id="@+id/inConfirmNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Confirm Number"
android:inputType="number"
<Button
android:id="@+id/btnLogin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="LOGIN"
<TextView
android:id="@+id/txtLoginResult"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center"
</LinearLayout>
MainActivity.java类的代码如下:
package com.theitroad.androidexpressobasics;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
EditText inUsername, inNumber, inConfirmNumber;
Button btnLogin;
TextView txtLoginResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
inUsername = findViewById(R.id.inUsername);
inNumber = findViewById(R.id.inNumber);
inConfirmNumber = findViewById(R.id.inConfirmNumber);
btnLogin = findViewById(R.id.btnLogin);
txtLoginResult = findViewById(R.id.txtLoginResult);
btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (TextUtils.isEmpty(inNumber.getText()))
Toast.makeText(getApplicationContext(), R.string.number_empty, Toast.LENGTH_SHORT).show();
else if (!(inNumber.getText().toString().equals(inConfirmNumber.getText().toString())))
Toast.makeText(getApplicationContext(), R.string.toast_error, Toast.LENGTH_SHORT).show();
else if (inUsername.getText().toString().trim().length() == 0)
Toast.makeText(getApplicationContext(), R.string.username_empty, Toast.LENGTH_SHORT).show();
else
txtLoginResult.setText("Hello " + inUsername.getText().toString().trim());
}
});
}
}
下面给出了strings.xml文件的代码:
编写Espresso测试
Espresso测试写在src中| androidTest文件夹文件。
默认情况下,将使用默认测试创建" ExampleInstrumentedTest.java"。
让我们其中编写一个测试:
package com.theitroad.androidexpressobasics;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
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 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.assertion.ViewAssertions.matches;
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.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static android.support.test.espresso.Espresso.onView;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.*;
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
public static final String USERNAME_TYPED = "Anupam";
public static final String LOGIN_TEXT = "Hello Anupam";
@Test
public void useAppContext() {
//Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.theitroad.androidexpressobasics", appContext.getPackageName());
}
@Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(
MainActivity.class);
@Test
public void loginClickedSuccess() {
onView(withId(R.id.inUsername))
.perform(typeText(USERNAME_TYPED));
onView(withId(R.id.inNumber))
.perform(typeText("12345"));
onView(withId(R.id.inConfirmNumber))
.perform(typeText("12345"));
onView(withId(R.id.btnLogin)).perform(click());
onView(withId(R.id.txtLoginResult)).check(matches(withText(LOGIN_TEXT)));
}
}
@Rule批注用于启动MainActivity。
在" loginClickedSuccess"内部,我们编写了一个成功的登录测试用例。
现在再写两个测试,我们将测试Toast是否正确显示。
在上面的类中添加以下方法:
@Test
public void shouldShowToastError() {
onView(withId(R.id.inUsername))
.perform(typeText(USERNAME_TYPED));
onView(withId(R.id.inNumber))
.perform(typeText("123456"));
onView(withId(R.id.inConfirmNumber))
.perform(typeText("12345"), closeSoftKeyboard());
onView(withId(R.id.btnLogin)).perform(click());
onView(withText(R.string.toast_error)).inRoot(withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView())))).check(matches(isDisplayed()));
}
@Test
public void shouldShowToastUsernameEmpty() {
onView(withId(R.id.inNumber))
.perform(typeText("12345"));
onView(withId(R.id.inConfirmNumber))
.perform(typeText("12345"));
onView(withId(R.id.btnLogin)).perform(click());
onView(withText(R.string.username_empty)).inRoot(withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView())))).check(matches(isDisplayed()));
}
最后一行用于检查Toast是否显示正确的字符串。
运行Espresso测试。
右键单击ExampleInstrumentationTest.java,然后按运行以在模拟器上启动自动化测试。
以下是实际应用程序的输出:
以下是运行上述自动UI测试时控制台中的输出:
Espresso测试记录
您也可以手动记录Espresso测试:
它将使用Espresso测试自动创建一个新文件,其中包含您在设备中执行的手动单击和操作。

