构建App的本地单元测试
如果App的测试目标单元对外没有依赖或者仅有简单的Android依赖,你应该考虑在本地开发机器上构建本地单元测试环境来完成App的单元测试。这种测试是非常高效的,在你每次运行测试的时候,它可以帮助你避免加载整个待测试的App进入真实的测试设备或者模拟器。因此,能将大幅度减少单元测试的执行时间,提高测试效率。
要进行这种单元测试,你通常需要借助mock框架,如Mockito,来满足任何的依赖关系。
设置你的测试环境
在你构建本地单元测试之前,确保你的工程按照测试计划中描述的那样配置了你的测试代码目录和工程依赖。
创建一个本地单元测试类
你的本地单元测试类应该按照JUnit 4 的测试类写法来写。JUnit 是Java平台使用最广泛的单元测试框架。最近发布的JUnit4框架相比之前的版本,可以让你编写出更干净,灵活的单元测试。不像之前基于JUnit3的Android单元测试,使用JUnit4 ,你不需要继承junit.framework.TestCase类。你也不需要在你的测试方法前添加test关键字,也不需要使用任何junit.framework或者是 junit.extensions包中的类。
为了创建一个基本的JUnit 4测试类,你需要创建一个java类,它包含一个或者多个测试方法。 一个测试方法使用@Test注解开始,同时包含你要测试和检验的单个功能的代码。
下面的实例向你展示了如何来实现一个本地单元测试类。测试方法emailValidator_CorrectEmailSimple_ReturnsTrue 验证正在测试中的App项目中的isValidEmail()方法是否返回正确的结果。
- 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));
- }
- …
- }
为了测试App中的那部分组件返回预期的结果,使用junit.Assert方法来进行预期结果的检验(或者断言)来比较正在测试下的组件的状态和预期的结果。为了让测试更具可读性,你可以使用 Hamcrest matchers (比如 is() 和 equalTo()方法)来将真实返回的结果和预期的结果进行匹配。
Mock Android 依赖
默认情况下, Android Plug-in for Gradle 执行你的本地单元测试借助一个修改过的android.jar 库,它不包含任何真实的代码。否则,如果你的单元测试如果调用了Android的具体方法,那么就会抛出一个异常来。
你可以使用mocking框架来让你的代码和外部依赖隔绝,以一种期待的方式和你的依赖进行交互这样会非常容易测试你的组件。通过mock对象替代Android依赖,当你在验证有Android依赖的方法调用时,可以让你的单元测试脱离android系统的一系列依赖。Java的Mockito框架(1.9.5 和更高版本)已经为Android的单元测试提供了完美的支持。使用了Mockito ,你可以配置mock对象当它被调用的时候让它返回一些指定的值。
为了使用该框架给你的本地单元测试添加一个mock对象,需遵从如下几步:
- 在build.gradle 文件中引入Mockito库的依赖。
- 在开始定义你的单元测试类之前,添加@RunWith(MockitoJUnitRunner.class)的注解。这个注解告诉Mockito测试运行器,你对该框架的使用是正确的,同时他可以简化mock对象的初始化。
- 为了对有Android 依赖的工程创建一个mock对象,在字段的定义前面,添加@Mock注解
- 为了对依赖的表现进行打桩,你可以声明一个条件当该条件满足的时候返回指定的值,通过调用when() 和 thenReturn()方法。
下面的例子展示了你该如何使用一个mock Context对象 创建一个单元测试:
- 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));
- }
- }
学习更多关于Mockito框架,查看Mockito API reference和SharedPreferencesHelperTest 类在sample code
运行本地单元测试
一切准备妥当,现在可以按照测试计划中所描述的那样来运行你的本地单元测试,完成App的单元测试。