Android的测试基于JUnit。
测试种类
- Local unit tests
目录:module-name/src/test/java/。
运行于本地JVM。测试文件中仅包含java代码,不使用Android相关API,或使用到的API可通过mock对象代替。 - Instrumented tests
目录:module-name/src/androidTest/java/。
运行于模拟器或真机。测试文件中需要使用Android相关API。系统会打包一个测试apk和一个实际apk,这2个apk运行在同一个进程。
大类别 | 子类别 | 描述 |
---|---|---|
单元测试(Unit tests) | Local Unit Tests | 运行于本地JVM,不依赖Android Framework或使用mock对象 |
Instrumented Unit Tests | 运行于模拟器或真机,可以使用与设备相关的信息,如app的Context。用于需依赖Android Framework或mock对象无法满足时 | |
集成测试(Integration tests) | app内组件测试 | 验证app的行为与预期是否一致。可使用UI测试框架如Espresso |
跨app组件测试 | 验证用户app间或用户app与系统app间的行为。可使用UI测试框架如UI Automator |
Unit Testing
- Robolectric
- JUnit
Instrumentation Testing
- Espresso
- UIAutomator
- Google Android Testing
- Robotium
- Selendroid
本地单元测试(Local Unit Tests)
目录:module-name/src/test/java/
JUnit
只可测试Java代码,如果需要依赖Android API,可以使用Mockito库来mock对象。
JUnit4与JUnit3相比,测试类不再需要继承自junit.framework.TestCase,测试方法不再需要“test”前缀,也不再需要使用junit.framework或junit.extensions包下的类。
使用步骤
1. 添加依赖
在build.gradle(Module:app)中添加JUnit4依赖。
testCompile 'junit:junit:4.12'
// 可选
// testCompile 'org.mockito:mockito-core:1.10.19'
2. 创建测试类
光标置于类名上,Option+Enter,Create Test,选择JUnit4和“setUp/@Before”,勾选要生成的测试方法。
3. 编写测试
使用JUnit框架提供的断言来编写自己的测试。
import org.junit.Test;
import java.util.regex.Pattern;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class EmailValidatorTest {
@Test
public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
assertThat(EmailValidator.isValidEmail("name@email.com"), is(true));
}
...
}
4. 运行测试
有以下几种方法:
- 运行单个测试文件,在Project窗口下,右键测试文件,点击Run;
- 运行测试文件中的某些方法或所有方法,右键要运行的方法,点击Run(快捷键Ctrl+R);
- 运行某个目录下的所有测试,右键该目录,选择Run tests;
- 命令行./gradlew test。
mock Android依赖
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.CoreMatchers.*;
import static org.mockito.Mockito.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import android.content.SharedPreferences;
@RunWith(MockitoJUnitRunner.class)
public class UnitTestSample {
private static final String FAKE_STRING = "HELLO WORLD";
@Mock
Context mMockContext;
@Test
public void readStringFromContext_LocalizedString() {
// Given a mocked Context injected into the object under test...
when(mMockContext.getString(R.string.hello_word))
.thenReturn(FAKE_STRING);
ClassUnderTest myObjectUnderTest = new ClassUnderTest(mMockContext);
// ...when the string is returned from the object under test...
String result = myObjectUnderTest.getHelloWorldString();
// ...then the result should be the expected one.
assertThat(result, is(FAKE_STRING));
}
}
Robolectric
Mock了部分Android的API,可以直接在JVM上调用Android相关类、方法,可以使用Context。
设备单元测试(Instrumented Unit Tests)
目录:module-name/src/androidTest/java/
测试支持库(Testing Support Library)包含JUnit 4 test runner(AndroidJUnitRunner)和UI测试API(Espresso和UI Automator)。
使用步骤
1. 配置依赖
在Project的gradle配置中添加如下依赖:
dependencies {
androidTestCompile 'com.android.support:support-annotations:24.0.0'
androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.android.support.test:rules:0.5'
// Optional -- Hamcrest library
//androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
// Optional -- UI testing with Espresso
//androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
// Optional -- UI testing with UI Automator
//androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
}
注:若配置中同时包含support-annotations库的compile依赖和espresso-core库的androidTestCompile依赖,可能会因依赖冲突导致build失败,可进行如下配置:
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' })
在module的gradle配置中添加如下配置,以指定AndroidJUnitRunner作为默认的Test Instrumentation Runner。
android {
defaultConfig {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
2. 创建测试类
在测试类前添加@RunWith(AndroidJUnit4.class)
注解。
import android.os.Parcel;
import android.support.test.runner.AndroidJUnit4;
import android.util.Pair;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class LogHistoryAndroidUnitTest {
public static final String TEST_STRING = "This is a string";
public static final long TEST_LONG = 12345678L;
private LogHistory mLogHistory;
@Before
public void createLogHistory() {
mLogHistory = new LogHistory();
}
@Test
public void logHistory_ParcelableWriteRead() {
// Set up the Parcelable object to send and receive.
mLogHistory.addEntry(TEST_STRING, TEST_LONG);
// Write the data.
Parcel parcel = Parcel.obtain();
mLogHistory.writeToParcel(parcel, mLogHistory.describeContents());
// After you're done with writing, you need to reset the parcel for reading.
parcel.setDataPosition(0);
// Read the data.
LogHistory createdFromParcel = LogHistory.CREATOR.createFromParcel(parcel);
List<Pair<String, Long>> createdFromParcelData = createdFromParcel.getData();
// Verify that the received data is correct.
assertThat(createdFromParcelData.size(), is(1));
assertThat(createdFromParcelData.get(0).first, is(TEST_STRING));
assertThat(createdFromParcelData.get(0).second, is(TEST_LONG));
}
}
3. 创建测试集(Create a test suite)
测试集将多个测试组织在一起,测试集置于测试包中(test package),包名一般以.suite结尾。
import com.example.android.testing.mysample.CalculatorAddParameterizedTest;
import com.example.android.testing.mysample.CalculatorInstrumentationTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
// Runs all unit tests.
@RunWith(Suite.class)
@Suite.SuiteClasses({CalculatorInstrumentationTest.class,
CalculatorAddParameterizedTest.class})
public class UnitTestSuite {}
4. 运行测试
有以下几种方法:
- 运行单个测试文件,在Project窗口下,右键测试文件,点击Run;
- 运行测试文件中的某些方法或所有方法,右键要运行的方法,点击Run(快捷键Ctrl+R);
- 运行某个目录下的所有测试,右键该目录,选择Run tests;
UI测试
目录:module-name/src/androidTest/java/
单APP UI测试(Espresso)
使用步骤
1. 添加依赖
在build.gradle(Module:app)中添加。
...
android {
...
defaultConfig {
...
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
dependencies {
...
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2') {
// Necessary if your app targets Marshmallow (since Espresso
// hasn't moved to Marshmallow yet)
exclude group: 'com.android.support', module: 'support-annotations'
}
androidTestCompile('com.android.support.test:runner:0.3') {
// Necessary if your app targets Marshmallow (since the test runner
// hasn't moved to Marshmallow yet)
exclude group: 'com.android.support', module: 'support-annotations'
}
}
2. 创建测试类
在src/androidTest/java目录下添加测试类,测试类的包最好与相应的类的包保持一致。
3. 编写测试
示例如下:
// MainActivityInstrumentationTest.java
import static android.support.test.espresso.Espresso.onView;
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.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
// Tests for MainActivity
public class MainActivityInstrumentationTest {
// Preferred JUnit 4 mechanism of specifying the activity to be launched before each test
@Rule
public ActivityTestRule<MainActivity> activityTestRule =
new ActivityTestRule<>(MainActivity.class);
// Looks for an EditText with id = "R.id.etInput"
// Types the text "Hello" into the EditText
// Verifies the EditText has text "Hello"
@Test
public void validateEditText() {
onView(withId(R.id.etInput)).perform(typeText("Hello")).check(matches(withText("Hello")));
// 上面使用了很多静态引用,以保证代码易读性。
// 如果不使用静态引用,代码如下:
Espresso.onView(ViewMatchers.withId(R.id.etInput))
.perform(ViewActions.typeText("Hello"))
.check(ViewAssertions.matches(ViewMatchers.withText("Hello")));
}
}
onView、perform、check方法的返回类型均为ViewInteraction。
Espresso测试的标准模式是查找一个View(ViewMatchers),在该View上做一些事情(ViewActions),然后验证该View的一些属性(ViewAssertions)。
4. 运行测试
- 使用Android Studio运行单个测试:右键测试类,选择Run,然后在控制台中查看结果。
- 使用gradle运行所有测试:打开Gradle Window,在Tasks->verification下找到connectedDebugAndroidTest,右键选中然后选择Run。会在以下位置生成测试报告app/build/reports/androidTests/connected/index.html。
多APP UI测试(UI Automator)
暂略。
参考
Getting Started with Testing
Building Local Unit Tests
Building Instrumented Unit Tests
Testing UI for a Single App
Testing UI for Multiple Apps
在Android Studio中进行单元测试和UI测试
Android Testing Options
Unit Testing with Robolectric
UI Testing with Espresso
Robolectric vs Android Test Framework
蘑菇街支付金融Android单元测试实践