辛苦堆砌,转载请注明出处,谢谢!
espresso是google官方提供的测试框架,可以用来对Android的UI行为进行测试,详细的可以从espresso的官网查看相关的文档,地址如下:
https://google.github.io/android-testing-support-library/docs/espresso/intents/index.html
本文主要借助于espresso,主要提供一种Android进行测试驱动开发的思路,本人也是刚刚开始尝试使用测试驱动开发,不足之处还请见谅。使用espresso,注意build.gradle(module::app)的dependencies
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:24.2.1'
testCompile 'junit:junit:4.12'
androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'
}
Demo很简单,MainActivity上有一个TextView,文本为Hello World,默认不可见的,点击一个Button,上有文本“点击”,可以切换TextView的可见性。我们先给出MainActivity的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
android:gravity="center"
tools:context="com.yjp.espressodemo.MainActivity">
<TextView
android:id="@+id/helloWorldTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/clickButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
可以看到布局很基础,没有加入任何功能,只是给控件赋值了id,然后我们在androidTest测试目录添加一个类,内容如下:
package com.yjp.espressodemo;
import android.content.res.Resources;
import android.support.test.InstrumentationRegistry;
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 static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class MainActivityTest {
@Rule
public IntentsTestRule<MainActivity> mIntentsRule=
new IntentsTestRule<>(MainActivity.class);
@Test
public void viewTextTest() {
Resources resources = mIntentsRule.getActivity().getResources();
checkText(R.id.helloWorldTextView, resources.getString(R.string.hello_world));
checkText(R.id.clickButton, resources.getString(R.string.click));
}
private void checkText(int id, String text) {
onView(withId(id)).check(matches(withText(text)));
}
}
我们只有一个测试任务,viewTextTest,用来测试View上的文本是否符合要求,现在的话编译无法通过,我们在strings.xml中添加字符串资源。
<resources>
<string name="app_name">EspressoDemo</string>
<string name="hello_world">Hello World</string>
<string name="click">点击</string>
</resources>
这个时候编译可以通过了,然后在该类的类文件上点击右键,单击Run 'MainActivityTest',运行测试,注意:该测试要有设备或者虚拟机才能正常运行。可以想到,测试不会通过,因为我们的文本不对。我们给控件添加文本,此时,布局变为
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
android:gravity="center"
tools:context="com.yjp.espressodemo.MainActivity">
<TextView
android:id="@+id/helloWorldTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"/>
<Button
android:id="@+id/clickButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/click"/>
</LinearLayout>
测试通过,然后我们添加新的测试方法
@Test
public void helloWorldTextViewGoneWhenStart() {
checkVisibility(R.id.helloWorldTextView, ViewMatchers.Visibility.GONE);
}
private void checkVisibility(int id, ViewMatchers.Visibility visibility) {
onView(withId(id))
.check(matches(withEffectiveVisibility(visibility)));
}
我们要保证开始时候TextView不可见,是GONE的状态,运行测试,不会通过,我们为了使测试通过,在布局文件中给helloWorldTextView添加属性
android:visibility="gone"
再次运行测试,很好,通过了。再添加一个测试用例,看看点击一下clickButton的效果
@Test
public void clickClickButtonOnce() {
clickButton(R.id.clickButton);
checkVisibility(R.id.helloWorldTextView, ViewMatchers.Visibility.VISIBLE);
}
private void clickButton(int id) {
onView(withId(id)).perform(click());
}
我们点击了一下按钮,判断TextView的可见性是否变化,运行测试无法通过,我们在MainActivity中onCreate中添加代码如下
final TextView helloWorldTextView = (TextView) findViewById(R.id.helloWorldTextView);
Button clickButton = (Button) findViewById(R.id.clickButton);
clickButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
helloWorldTextView.setVisibility(View.VISIBLE);
}
});
运行测试,测试通过。你可能会有疑问,这样的代码,我们点击两次按钮不就不对了,的确如此,不过有点想多了,我们只要保证每一个测试用例通过就好了,我们添加新的测试用例
@Test
public void clickClickButtonTwice() {
clickButton(R.id.clickButton);
clickButton(R.id.clickButton);
checkVisibility(R.id.helloWorldTextView, ViewMatchers.Visibility.GONE);
}
点击两下按钮,测试当然又不能通过,我们修改onClick的代码
@Override
public void onClick(View v) {
if (helloWorldTextView.getVisibility() == View.GONE) {
helloWorldTextView.setVisibility(View.VISIBLE);
} else {
helloWorldTextView.setVisibility(View.GONE);
}
}
好了,我们的代码又通过测试了XD。至此,我们满足了开发需求。不过通过测试驱动开发的学习,个人感觉也有一定的负担,那就是对测试框架的学习,如果对测试框架不熟悉,可能导致在编写测试用例上花费很多的时间,项目被拖延很长时间,但是测试用例带来后续回归测试的好处是不言而喻的。