Android单元测试

2016-10-26  本文已影响92人  sylcrq

关键词:Android Testing, JUnit, Mockito, Espresso, Robolectric

Android单元测试可以分为两类:

Android Test

JUnit 4 注解

1. Local Unit Tests

build.gradle中配置测试依赖:

dependencies {
    ......
    testCompile 'junit:junit:4.12'
    testCompile 'org.robolectric:robolectric:3.0'
    testCompile 'org.hamcrest:hamcrest-all:1.3'
    testCompile 'org.mockito:mockito-core:1.10.19'
}

一个简单的例子:

public class EmailValidatorTest {
    @Test
    public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
        assertThat(EmailValidator.isValidEmail("name@email.com"), is(true));
    }
    ...
}

By default, the Android Plug-in for Gradle executes your local unit tests against a modified version of the android.jar library, which does not contain any actual code. Instead, method calls to Android classes from your unit test throw an exception.

使用 Mockito mock 测试代码中对Android的依赖:

@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

Robolectric is a unit test framework that de-fangs the Android SDK jar so you can test-drive the development of your Android app. Tests run inside the JVM on your workstation in seconds.

testCompile "org.robolectric:robolectric:3.1.4"
@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class)
public class SandwichTest {
}

Note that you must specify the constants field which points to the BuildConfig.class generated by the build system. Robolectric uses the constants in the class to compute the output paths used by Gradle when building your project. Without these values, Robolectric will not be able to find your merged manifest, resources, or assets.

一个简单的例子:

@RunWith(RobolectricTestRunner.class)
public class WelcomeActivityTest {

    @Test
    public void clickingLogin_shouldStartLoginActivity() {
        WelcomeActivity activity = Robolectric.setupActivity(WelcomeActivity.class);
        activity.findViewById(R.id.login).performClick();

        Intent expectedIntent = new Intent(activity, LoginActivity.class);
        assertThat(shadowOf(activity).getNextStartedActivity()).isEqualTo(expectedIntent);
    }
}

The primary way to customize Robolectric is done via the @Config annotation.

  1. Configure SDK Level
    Robolectric 默认会运行 manifest 中指定的targetSdkVersion版本,如果某些代码需要在不同的SDK版本下测试,可以如下设置:
@Config(sdk = Build.VERSION_CODES.JELLY_BEAN)
public class SandwichTest {

    @Config(sdk = Build.VERSION_CODES.KITKAT)
    public void getSandwich_shouldReturnHamSandwich() {
    }
}
  1. Configure Application Class
    Robolectric 默认会创建 manifest 中指定的Application类,如果需要替换为其他自定义,可以如下设置:
@Config(application = CustomApplication.class)
public class SandwichTest {

    @Config(application = CustomApplicationOverride.class)
    public void getSandwich_shouldReturnHamSandwich() {
    }
}
  1. Configure Resource Paths
    自定义manifest,resource和assets目录的路径,如果你使用的是自定义build system的话,会需要用到。

  2. Config Properties
    上述的配置既可以在@Config注解中指定,也可以写在配置文件中。
    Create a file named robolectric.properties and make sure it can be found on the classpath.

  3. System Properties

android {
  testOptions {
    unitTests.all {
      systemProperty 'robolectric.dependency.repo.url', 'https://local-mirror/repo'
      systemProperty 'robolectric.dependency.repo.id', 'local'
    }
  }
}
Activity activity = Robolectric.buildActivity(MyAwesomeActivity.class).create().get();
<string name="not_overridden">Not Overridden</string>
<string name="overridden">Unqualified value</string>
<string name="overridden_twice">Unqualified value</string>

values-en/strings.xml

<string name="overridden">English qualified value</string>
<string name="overridden_twice">English qualified value</string>

values-en-port/strings.xml

<string name="overridden_twice">English portrait qualified value</string>
@Test
@Config(qualifiers="en-port")
public void shouldUseEnglishAndPortraitResources() {
  final Context context = RuntimeEnvironment.application;
  assertThat(context.getString(R.id.not_overridden)).isEqualTo("Not Overridden");
  assertThat(context.getString(R.id.overridden)).isEqualTo("English qualified value");
  assertThat(context.getString(R.id.overridden_twice)).isEqualTo("English portrait qualified value");
}

Robolectric defines many shadow classes, which modify or extend the behavior of classes in the Android OS. When an Android class is instantiated, Robolectric looks for a corresponding shadow class, and if it finds one it creates a shadow object to associate with it. Every time a method is invoked on an Android class, Robolectric ensures that the shadow class' corresponding method is invoked first (if there is one), so it has a chance to work its magic. This applies to all methods, even static and final methods, because Robolectric is extra tricky!

2. Instrumented Unit Tests

build.gradle中配置测试依赖:

android {
    ...
    defaultConfig {
        ...
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
}

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'
}

参考资料:

上一篇 下一篇

猜你喜欢

热点阅读