指定Test Runner为Android JUnit Test Runner
前面介绍的JUnit3测试和Android基本测试,都基于Instrumentation Test Runner,之后谷歌又推出了Android JUnit Test Runner。根据官方的资料,前者只支持JUnit3,而后者还可以支持JUnit4。
http://developer.android.com/intl/zh-cn/tools/testing-support-library/index.html
在app模块的build.gradle中,可以指定Test Runner为Android JUnit Test Runner,写法如下。在dependencies中,testCompile表示JUnit测试时编译,androidTestCompile则表示Android Instrumentation Test时编译。
-
android {
-
defaultConfig {
-
// ...
-
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
-
}
-
packagingOptions {
-
exclude 'LICENSE.txt'
-
}
-
}
-
dependencies {
-
androidTestCompile 'com.android.support.test:runner:0.2'
-
}
配置完成后,即可运行JUnit4测试。除了代码格式不同,其他操作和前面的JUnit3一样,不再重复。
测试设备上的Test Runner
运行测试后,执行adb指令
adb shell pm list instrumentation
可以看到所有Test Runner
instrumentation:com.example.android.apis/.app.LocalSampleInstrumentation (target=com.example.android.apis)
instrumentation:com.jzj1993.unittest.test/android.support.test.runner.AndroidJUnitRunner (target=com.jzj1993.unittest)
还是在设置的所有应用中,可以看到Android JUnit Test Runner,其名称为Test-api,如图。
基于Espresso的测试
Android的测试,除了直接调用相关代码,还有个很常见的途径,就是通过交互界面来测试。如果直接用Instrumentation发送点击等事件来测试,实在非常麻烦。这时可以利用谷歌官方推出的开源框架Espresso做测试。
这里举一个最简单的带UI交互的测试例子。
配置espresso
Espresso基于AndroidJUnitRunner,因此需要进行设置;AndroidJUnitRunner中如果需要获取Activity实例,还需要TestRules包的支持。在build.gradle中包含AndroidJUnitRunner、TestRules和Espresso的完整配置如下。
-
apply plugin: 'com.android.application'
-
android {
-
defaultConfig {
-
// ...
-
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
-
}
-
packagingOptions {
-
exclude 'LICENSE.txt'
-
}
-
}
-
dependencies {
-
// ...
-
// 如果依赖项中有appcompat,尽量使用22.0.0,或解决依赖冲突
-
compile 'com.android.support:appcompat-v7:22.0.0'
-
androidTestCompile 'com.android.support.test:runner:0.2'
-
androidTestCompile 'com.android.support.test:rules:0.2'
-
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.1'
-
}
依赖冲突解决
注意,在一个稍复杂的项目中配置Espresso,很容易产生依赖项冲突。对于espresso-core:2.1,如果项目的依赖项中有appcompat-v7,尽可能将其版本改为22.0.0。也可以参考下文尝试解决。
《Gradle依赖项学习总结,dependencies、transitive、force、exclude的使用与依赖冲突解决》
http://wiki.sankuai.com/pages/viewpage.action?pageId=404573094
主要的两个冲突项是hamcrest-core和support-annotations,以下是我实际应用到一个项目中的gradle依赖项配置,可供参考。每个包的版本改动,都有可能导致冲突或不兼容。
-
configurations.all {
-
resolutionStrategy {
-
force 'org.hamcrest:hamcrest-core:1.1'
-
force 'com.android.support:support-annotations:22.0.0'
-
}
-
}
-
dependencies {
-
// ...
-
androidTestCompile 'com.android.support.test:runner:0.2'
-
androidTestCompile 'com.android.support.test:rules:0.2'
-
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.1'
-
}
创建待测试项目
这里创建一个TextView和一个Button,点击Button时TextView中的文字改变。activity_main.xml文件如下:
-
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-
android:layout_width="match_parent"
-
android:layout_height="match_parent"
-
android:gravity="center_horizontal"
-
android:orientation="vertical">
-
<TextView
-
android:id="@+id/text"
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
android:text="Text"
-
android:textSize="25sp" />
-
<Button
-
android:id="@+id/button"
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
android:text="Button" />
-
</LinearLayout>
对应的MainActivity如下:
-
public class MainActivity extends Activity {
-
@Override
-
protected void onCreate(Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
setContentView(R.layout.activity_main);
-
final TextView textView = (TextView) findViewById(R.id.text);
-
Button button = (Button) findViewById(R.id.button);
-
button.setOnClickListener(new View.OnClickListener() {
-
@Override
-
public void onClick(View v) {
-
textView.setText("Hello Android Test!");
-
}
-
});
-
}
-
}
创建测试类
在androidTest/java目录下创建一个MainActivityTest类。测试类中有一个TestCase,其作用是点击R.id.button控件,然后检测文本框是否展示了预期的文本。
-
package com.jzj1993.unittest;
-
import android.support.test.rule.ActivityTestRule;
-
import android.support.test.runner.AndroidJUnit4;
-
import android.test.suitebuilder.annotation.LargeTest;
-
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.action.ViewActions.click;
-
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 ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class);
-
@Test
-
public void sayHello() throws Exception {
-
onView(withId(R.id.button)).perform(click());
-
onView(withId(R.id.text)).check(matches(withText("Hello Android Test!")));
-
Thread.sleep(5000);
-
}
-
}
运行测试
运行测试的方法和前面一样。运行时,可以在Android设备上看到测试效果,按钮被点击,于是文本框展示指定的文本。延时5s测试执行完成后,App退出。Run和Event Log窗口中提示测试通过。
测试失败的情况
修改测试方法的文本,测试就会失败。
@Test
public void sayHello() {
onView(withId(R.id.button)).perform(click());
onView(withId(R.id.text)).check(matches(withText("Test Failed!")));
}