android测试主要有两种
1.本地测试(local test)
只在计算机中运行,这些测试运行在本地JVM中以减少执行时间。这种测试适合不需要android framework或者可以用模拟出的依赖来代替的测试。
2.设备测试(instrumentation test)
运行在android设备或者模拟器上的测试。这些测试需要使用到设备信息,如app的context。这种测试适合难以用mock代替的对象以及UI测试。
在最新的android studio(版本2.0)中,project已经分好了androidTest和test两个部分,前者用于设备测试,后者用于本地测试,从example中可见出区别。
以下详细讲两种测试的步骤:
本地测试
首先要配置好gradle的依赖信息
dependencies {
// Required -- JUnit 4 framework
testCompile 'junit:junit:4.12'
// Optional -- Mockito framework
testCompile 'org.mockito:mockito-core:1.10.19'
}
我们应该使用JUnit4来进行我们的测试开发。使用JUnit4,我们不再需要继承junit.framework.TestCase,我们也不再需要在方法名前以test作为前缀。
我们需要的是在测试方法前加上@Test的注释
我们可以用junit.Assert方法检车我们的返回值和期望值是否相同。
如果想让测试更加可读,我们可以使用Hamcrest matchers来进行匹配。
例如现在我们有一个User类
public class User{现在我们在测试中模拟一个用户,然后创建一个用户
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
将两个getAge方法进行对比
public class ExampleUnitTest {
@Mock
User mockUser;
User user;
@Before
public void setup(){
MockitoAnnotations.initMocks(this);
when(mockUser.getAge()).thenReturn(20);
user = new User("haha",20);
}
@Test
public void checkAge(){
assertEquals(mockUser.getAge(),user.getAge());
}
}
以下是android官方文档的sample:android文档传送门
import static org.hamcrest.MatcherAssert.assertThat;在官方例子中,就用了mock处理Context的问题
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));
}
}
mock的用法有很多,详细大家可以看《android开发进阶——从小工到专家》里面的介绍
给大家一个mockito官方文档的传送门:mock传送门
设备测试
设备测试运行在模拟器或者真机上,适合需要设备信息(如context)后者需要android framework组件(如Parcelable 或者 SharedPreference),可以减少mock的对象。 使设备测试还可以充分利用好android framework API,例如android testing support library。和本地测试一样,我们要配置好测试库的依赖
dependencies {
androidTestCompile 'com.android.support:support-annotations:23.0.1'
androidTestCompile 'com.android.support.test:runner:0.4.1'
androidTestCompile 'com.android.support.test:rules:0.4.1'
// 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.1'
// Optional -- UI testing with UI Automator
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1'
}
这里的测试库包括了JUnit4和用于UI测试的Espresso和UI Automator(两者分别用于白盒测试和黑盒测试,选择自己需要的来用就好了) Hamcrest是用于让断言(assert)函数更容易使用
为了让JUnit成为我们默认的测试运行器,我们需要在app 模块gradle文件中添加
android {例如这样:
defaultConfig {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
<span style="font-family: Arial, Helvetica, sans-serif;">apply plugin: 'com.android.application'</span>
android { compileSdkVersion 22 buildToolsVersion "22" defaultConfig { applicationId "com.my.awesome.app" minSdkVersion 10 targetSdkVersion 22.0.1 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" }}dependencies { // App's dependencies, including test compile 'com.android.support:support-annotations:22.2.0' // Testing-only dependencies androidTestCompile 'com.android.support.test:runner:0.5' androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'}
创建测试类时要在前面加上@RunWith(AndroidJUnit4.class)下面是范例
import android.os.Parcel;我们还可以 创建一个以.suite结尾的包,在里面创建一个UnitTestSuite类,在类前加上
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));
}
}
@RunWith(Suite.class)
和@Suite.SuitClasses()
在SuiteClasses中列出测试用例
例子:
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 {}
在后面我还会讲述UI测试库的用法,谢谢大家关注