- Local tests
本地端的測試,程式碼只會運行在 JVM 上,所以執行效率最佳。多用於測試與 Android framework 沒有相依性的程式碼,或是其相依能被 mock objects 所取代。(Robolectric 也可以解決這個問題,見 Ref 3)
本地端的測試,程式碼只會運行在 JVM 上,所以執行效率最佳。多用於測試與 Android framework 沒有相依性的程式碼,或是其相依能被 mock objects 所取代。(Robolectric 也可以解決這個問題,見 Ref 3)
- Instrumented tests
跑在實體機器或模擬器上的測試。這些測試需要取得裝置上的一些資訊,如 Context 物件,或有其他不容易被 mock objects 所取代的相依類別。
跑在實體機器或模擬器上的測試。這些測試需要取得裝置上的一些資訊,如 Context 物件,或有其他不容易被 mock objects 所取代的相依類別。
建立 Local Unit Test Class
在 Android 中,建立單元測試需要用到 JUnit 這個已在 Java 世界中被廣泛被使用的 Unit Testing Framework,目前最新的版本是 JUnit 4,JUnit 4 不像前一版 JUnit 3 需要讓 test classes繼承 junit.framework.TestCase,更不限制 method 的命名要以 "test" 為前綴字。
測試的程式碼需要放在路徑 src/test/java 之下。
測試的程式碼需要放在路徑 src/test/java 之下。
範例如下:
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)); } ... }
在 gradle.build 裡宣告:
dependencies { // Required -- JUnit 4 framework testCompile 'junit:junit:4.12' // Optional -- Mockito framework testCompile 'org.mockito:mockito-core:1.+' }
建立 Instrumented Test Class
需要用到 JUnit 4 test runner,而且測試的程式碼需要放在路徑 src/androidTest/java 之下。
此外 AndroidJUnitRunner 已經用來取代舊的 InstrumentationTestRunner 和 MultiDexTestRunner(自己繼承 AndroidJUnitRunner 來實作 AndroidJUnitMultiDexRunner )。若需要 Context 的話,可以透過 InstrumentationRegistry.getContext() 來取得物件(不用再繼承 InstrumentationTestCase 了)。
範例如下:
在 gradle.build 裡宣告: (Note: 這裡可能會遇到 support-annotations 版本衝突的問題)
Ref:
此外 AndroidJUnitRunner 已經用來取代舊的 InstrumentationTestRunner 和 MultiDexTestRunner(自己繼承 AndroidJUnitRunner 來實作 AndroidJUnitMultiDexRunner )。若需要 Context 的話,可以透過 InstrumentationRegistry.getContext() 來取得物件(不用再繼承 InstrumentationTestCase 了)。
範例如下:
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> 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)); } }
在 gradle.build 裡宣告: (Note: 這裡可能會遇到 support-annotations 版本衝突的問題)
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' }
Ref:
- Building Effective Unit Tests
https://developer.android.com/training/testing/unit-testing/index.html - Unit tests with Mockito - Tutorial
http://www.vogella.com/tutorials/Mockito/article.html - Easy Testing with Android Studio
http://blog.element84.com/easy-testing-with-android-studio.html
沒有留言:
張貼留言