国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Android Unit Test

這篇具有很好參考價(jià)值的文章主要介紹了Android Unit Test。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

一、測(cè)試基礎(chǔ)知識(shí)

1.1 測(cè)試級(jí)別

測(cè)試金字塔(如圖 2 所示)說(shuō)明了應(yīng)用應(yīng)如何包含三類測(cè)試(即小型、中型和大型測(cè)試):

  • 小型測(cè)試是指單元測(cè)試,用于驗(yàn)證應(yīng)用的行為,一次驗(yàn)證一個(gè)類。

  • 中型測(cè)試是指集成測(cè)試,用于驗(yàn)證模塊內(nèi)堆棧級(jí)別之間的互動(dòng)或相關(guān)模塊之間的互動(dòng)。

  • 大型測(cè)試是指端到端測(cè)試,用于驗(yàn)證跨越了應(yīng)用的多個(gè)模塊的用戶操作流程。

沿著金字塔逐級(jí)向上,從小型測(cè)試到大型測(cè)試,各類測(cè)試的保真度逐級(jí)提高,但維護(hù)和調(diào)試工作所需的執(zhí)行時(shí)間和工作量也逐級(jí)增加。因此,您編寫(xiě)的單元測(cè)試應(yīng)多于集成測(cè)試,集成測(cè)試應(yīng)多于端到端測(cè)試。雖然各類測(cè)試的比例可能會(huì)因應(yīng)用的用例不同而異,但我們通常建議各類測(cè)試所占比例如下:小型測(cè)試占 70%,中型測(cè)試占 20%,大型測(cè)試占 10%

圖1 測(cè)試金字塔,顯示了應(yīng)用的測(cè)試套件應(yīng)包含的三類測(cè)試

1.2 迭代創(chuàng)建和測(cè)試代碼

迭代開(kāi)發(fā)某項(xiàng)功能時(shí),您可以先編寫(xiě)一個(gè)新測(cè)試,也可以將用例和斷言添加到現(xiàn)有單元測(cè)試。測(cè)試最初會(huì)失敗,因?yàn)樵摴δ苌形磳?shí)現(xiàn)。

務(wù)必考慮隨著設(shè)計(jì)新功能而出現(xiàn)的責(zé)任單元。對(duì)于每個(gè)單元,您需要編寫(xiě)相應(yīng)的單元測(cè)試。您的單元測(cè)試應(yīng)幾乎囊括與單元的所有可能的互動(dòng),包括標(biāo)準(zhǔn)互動(dòng)、無(wú)效輸入以及資源不可用的情況。應(yīng)盡可能利用 Jetpack 庫(kù);當(dāng)您使用這些經(jīng)過(guò)充分測(cè)試的庫(kù)時(shí),您可以專注于驗(yàn)證您的應(yīng)用特有的行為。

圖2 與由測(cè)試驅(qū)動(dòng)的迭代開(kāi)發(fā)關(guān)聯(lián)的兩個(gè)周期

完整的工作流(如圖 1 所示)包含一系列嵌套的迭代周期,其中一個(gè)由界面驅(qū)動(dòng)的漫長(zhǎng)而緩慢的周期用來(lái)測(cè)試代碼單元的集成。您可以使用更短且更快的開(kāi)發(fā)周期來(lái)測(cè)試單元本身。這一組周期一直持續(xù)到您的應(yīng)用滿足每個(gè)用例為止。

二、構(gòu)建單元測(cè)試

單元測(cè)試是應(yīng)用測(cè)試策略中的基本測(cè)試。通過(guò)針對(duì)代碼創(chuàng)建和運(yùn)行單元測(cè)試,您可以輕松驗(yàn)證各個(gè)單元的邏輯是否正確。在每次構(gòu)建后運(yùn)行單元測(cè)試可幫助您快速捕捉和修復(fù)由應(yīng)用的代碼更改導(dǎo)致的軟件回歸。

單元測(cè)試通常以可重復(fù)的方式運(yùn)用盡可能小的代碼單元(可能是方法、類或組件)的功能。當(dāng)您需要驗(yàn)證應(yīng)用中特定代碼的邏輯時(shí),應(yīng)構(gòu)建單元測(cè)試。例如,如果您正在對(duì)某個(gè)類進(jìn)行單元測(cè)試,測(cè)試可能會(huì)檢查該類是否處于正確狀態(tài)。通常,代碼單元在隔離的環(huán)境中進(jìn)行測(cè)試;您的測(cè)試僅影響和監(jiān)控對(duì)該單元的更改。您可以使用依賴項(xiàng)提供器(如 Robolectric)或模擬框架將您的單元與其依賴項(xiàng)隔離開(kāi)來(lái)。

2.1 構(gòu)建本地單元測(cè)試

設(shè)置測(cè)試環(huán)境

在 Android Studio 項(xiàng)目中,您必須將本地單元測(cè)試的源文件存儲(chǔ)在 module-name/src/test/java/ 中。當(dāng)您創(chuàng)建新項(xiàng)目時(shí),此目錄已存在。

您還需要為項(xiàng)目配置測(cè)試依賴項(xiàng),以使用 JUnit 4 框架提供的標(biāo)準(zhǔn) API。如果您的測(cè)試需要與 Android 依賴項(xiàng)互動(dòng),請(qǐng)?zhí)砑?Robolectric 或 Mockito 庫(kù)以簡(jiǎn)化您的本地單元測(cè)試。

在應(yīng)用的頂級(jí) build.gradle 文件中,請(qǐng)將以下庫(kù)指定為依賴項(xiàng):

 

dependencies { // Required -- JUnit 4 framework testImplementation 'junit:junit:4.12' // Optional -- Robolectric environment testImplementation 'androidx.test:core:1.0.0' // Optional -- Mockito framework testImplementation 'org.mockito:mockito-core:1.10.19' }

創(chuàng)建本地單元測(cè)試類

本地單元測(cè)試類應(yīng)編寫(xiě)為 JUnit 4 測(cè)試類。JUnit 是最受歡迎且應(yīng)用最廣泛的 Java 單元測(cè)試框架。與原先的版本相比,JUnit 4 可讓您以更簡(jiǎn)潔且更靈活的方式編寫(xiě)測(cè)試,因?yàn)?JUnit 4 不要求您執(zhí)行以下操作:

  • 擴(kuò)展 junit.framework.TestCase 類。

  • 在測(cè)試方法名稱前面加上 'test' 關(guān)鍵字作為前綴。

  • 使用 junit.frameworkjunit.extensions 軟件包中的類。

如需創(chuàng)建基本的 JUnit 4 測(cè)試類,請(qǐng)創(chuàng)建包含一個(gè)或多個(gè)測(cè)試方法的類。測(cè)試方法以 @Test 注釋開(kāi)頭,并且包含用于運(yùn)用和驗(yàn)證要測(cè)試的組件中的單項(xiàng)功能的代碼。

以下示例展示了如何實(shí)現(xiàn)本地單元測(cè)試類。測(cè)試方法 emailValidator_CorrectEmailSimple_ReturnsTrue 驗(yàn)證被測(cè)應(yīng)用中的 isValidEmail() 方法是否返回正確的結(jié)果。

 

import com.google.common.truth.Truth.assertThat import org.junit.Test class EmailValidatorTest { @Test fun emailValidator_CorrectEmailSimple_ReturnsTrue() { assertThat(EmailValidator.isValidEmail("name@email.com")).isTrue() } }

如需創(chuàng)建容易讀懂的測(cè)試來(lái)評(píng)估應(yīng)用中的組件是否返回預(yù)期的結(jié)果,我們建議使用 Truth 庫(kù)和 Android Assertions 中的類,如前面的示例所示。如需詳細(xì)了解 Truth 和 Android Assertions 支持哪些類型的邏輯驗(yàn)證,請(qǐng)參閱介紹如何創(chuàng)建更容易讀懂的斷言的部分。

不過(guò),如果您更愿意使用 junit.Assert 方法或 Hamcrest 匹配器(如 is()equalTo() 方法)來(lái)比較預(yù)期結(jié)果與實(shí)際結(jié)果,也可以改用這些庫(kù)。

添加框架依賴項(xiàng)

如果您的測(cè)試與多個(gè) Android 框架依賴項(xiàng)互動(dòng),或以復(fù)雜的方式與這些依賴項(xiàng)互動(dòng),請(qǐng)使用 AndroidX Test 提供的 Robolectric 工件。Robolectric 在本地 JVM 或真實(shí)設(shè)備上執(zhí)行真實(shí)的 Android 框架代碼和原生框架代碼的虛假對(duì)象。

以下示例展示了如何創(chuàng)建使用 Robolectric 的單元測(cè)試:

app/build.gradle

 

android { // ... testOptions { unitTests.includeAndroidResources = true } }

MyLocalUnitTestClass

 

import android.content.Context import androidx.test.core.app.ApplicationProvider import com.google.common.truth.Truth.assertThat import org.junit.Test private const val FAKE_STRING = "HELLO_WORLD" class UnitTestSample { val context = ApplicationProvider.getApplicationContext<Context>() @Test fun readStringFromContext_LocalizedString() { // Given a Context object retrieved from Robolectric... val myObjectUnderTest = ClassUnderTest(context) // ...when the string is returned from the object under test... val result: String = myObjectUnderTest.getHelloWorldString() // ...then the result should be the expected one. assertThat(result).isEqualTo(FAKE_STRING) } }

添加模擬依賴項(xiàng)

默認(rèn)情況下,Android Plug-in for Gradle 針對(duì)一個(gè)修改版 android.jar 庫(kù)(不包含任何實(shí)際代碼)執(zhí)行本地單元測(cè)試。從單元測(cè)試對(duì) Android 類的方法調(diào)用會(huì)拋出異常。這是為了確保您僅測(cè)試代碼,而不依賴于 Android 平臺(tái)的任何特定行為,即您未明確構(gòu)建或模擬的行為。

模擬 Android 依賴項(xiàng)

如果您的測(cè)試對(duì) Android 的依賴性極小,并且您需要在應(yīng)用中測(cè)試組件與其依賴項(xiàng)之間的特定互動(dòng),請(qǐng)使用模擬框架對(duì)代碼中的外部依賴項(xiàng)打樁。這樣,您就可以輕松地測(cè)試組件是否按預(yù)期方式與依賴項(xiàng)互動(dòng)。通過(guò)用模擬對(duì)象代替 Android 依賴項(xiàng),您可以將單元測(cè)試與 Android 系統(tǒng)的其余部分隔離,同時(shí)驗(yàn)證是否調(diào)用了這些依賴項(xiàng)中的正確方法。適用于 Java(版本 1.9.5 及更高版本)的 Mockito 模擬框架提供了與 Android 單元測(cè)試的兼容性。通過(guò) Mockito,您可以將模擬對(duì)象配置為在被調(diào)用時(shí)返回某個(gè)特定值。

如需使用此框架將模擬對(duì)象添加到本地單元測(cè)試,請(qǐng)遵循以下編程模型:

  1. build.gradle 文件中添加 Mockito 庫(kù)依賴項(xiàng),如設(shè)置測(cè)試環(huán)境中所述。

  2. 在單元測(cè)試類定義的開(kāi)頭,添加 @RunWith(MockitoJUnitRunner.class) 注釋。此注釋可告知 Mockito 測(cè)試運(yùn)行程序驗(yàn)證您對(duì)框架的使用是否正確無(wú)誤,并簡(jiǎn)化了模擬對(duì)象的初始化。

  3. 如需為 Android 依賴項(xiàng)創(chuàng)建模擬對(duì)象,請(qǐng)?jiān)谧侄温暶髑疤砑?@Mock 注釋。

  4. 如需模擬依賴項(xiàng)的行為,您可以使用 when()thenReturn() 方法來(lái)指定某種條件以及滿足該條件時(shí)的返回值。

以下示例展示了如何創(chuàng)建使用模擬 Context 對(duì)象的單元測(cè)試。

 

import android.content.Context import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnitRunner private const val FAKE_STRING = "HELLO WORLD" @RunWith(MockitoJUnitRunner::class) class UnitTestSample { @Mock private lateinit var mockContext: Context @Test fun readStringFromContext_LocalizedString() { // Given a mocked Context injected into the object under test... `when`(mockContext.getString(R.string.hello_word)) .thenReturn(FAKE_STRING) val myObjectUnderTest = ClassUnderTest(mockContext) // ...when the string is returned from the object under test... val result: String = myObjectUnderTest.getHelloWorldString() // ...then the result should be the expected one. assertThat(result, `is`(FAKE_STRING)) } }

錯(cuò)誤:“Method ... not mocked”

如果您運(yùn)行的測(cè)試從并未模擬的 Android SDK 調(diào)用 API,您會(huì)收到一條錯(cuò)誤,指出未模擬此方法。這是因?yàn)?,用于運(yùn)行單元測(cè)試的 android.jar 文件不包含任何實(shí)際代碼(這些 API 僅由設(shè)備上的 Android 系統(tǒng)映像提供)。

默認(rèn)情況下,所有方法都會(huì)拋出異常。這是為了確保單元測(cè)試僅測(cè)試代碼,而不依賴于 Android 平臺(tái)的任何特定行為,即您未明確模擬(如使用 Mockito 模擬)的行為。

如果拋出的異常會(huì)給測(cè)試帶來(lái)問(wèn)題,您可以通過(guò)在項(xiàng)目的頂級(jí) build.gradle 文件中添加以下配置來(lái)更改行為,以使方法返回 null 或 0:

 

android { ... testOptions { unitTests.returnDefaultValues = true } }

2.2 構(gòu)建插樁單元測(cè)試

插樁單元測(cè)試是在實(shí)體設(shè)備和模擬器上運(yùn)行的測(cè)試,此類測(cè)試可以利用 Android 框架 API 和輔助性 API,如 AndroidX Test。插樁測(cè)試提供的保真度比本地單元測(cè)試要高,但運(yùn)行速度要慢得多。因此,我們建議只有在必須針對(duì)真實(shí)設(shè)備的行為進(jìn)行測(cè)試時(shí)才使用插樁單元測(cè)試。AndroidX Test 提供了幾個(gè)庫(kù),可讓您在必要時(shí)更輕松地編寫(xiě)插樁單元測(cè)試。例如,Android Builder 類可讓您更輕松地創(chuàng)建本來(lái)難以構(gòu)建的 Android 數(shù)據(jù)對(duì)象。

設(shè)置測(cè)試環(huán)境

在 Android Studio 項(xiàng)目中,您必須將插樁測(cè)試的源文件存儲(chǔ)在 module-name/src/androidTest/java/ 中。此目錄在您創(chuàng)建新項(xiàng)目時(shí)已存在,并且包含一個(gè)插樁測(cè)試示例。

在開(kāi)始之前,您應(yīng)先添加 AndroidX Test API,以便為您的應(yīng)用快速構(gòu)建和運(yùn)行插樁測(cè)試代碼。AndroidX Test 包含 JUnit 4 測(cè)試運(yùn)行程序 (AndroidJUnitRunner) 和用于功能界面測(cè)試的 API(Espresso 和 UI Automator)。

您還需要為項(xiàng)目配置 Android 測(cè)試依賴項(xiàng),以使用 AndroidX Test 提供的測(cè)試運(yùn)行程序和規(guī)則 API。為了簡(jiǎn)化測(cè)試開(kāi)發(fā),您還應(yīng)添加 Hamcrest 庫(kù),該庫(kù)可讓您使用 Hamcrest 匹配器 API 創(chuàng)建更靈活的斷言。

在應(yīng)用的頂級(jí) build.gradle 文件中,您需要將以下庫(kù)指定為依賴項(xiàng):

 

dependencies { androidTestImplementation 'androidx.test:runner:1.1.0' androidTestImplementation 'androidx.test:rules:1.1.0' // Optional -- Hamcrest library androidTestImplementation 'org.hamcrest:hamcrest-library:1.3' // Optional -- UI testing with Espresso androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' // Optional -- UI testing with UI Automator androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' }

如需使用 JUnit 4 測(cè)試類,請(qǐng)務(wù)必在您的項(xiàng)目中將 AndroidJUnitRunner 指定為默認(rèn)插樁測(cè)試運(yùn)行程序,方法是在應(yīng)用的模塊級(jí) build.gradle 文件中添加以下設(shè)置:

 

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

創(chuàng)建插樁單元測(cè)試類

插樁單元測(cè)試類應(yīng)該是一個(gè) JUnit 4 測(cè)試類,它類似于有關(guān)如何創(chuàng)建本地單元測(cè)試類的部分中介紹的類。

如需創(chuàng)建 JUnit 4 插樁測(cè)試類,請(qǐng)將 AndroidJUnit4 指定為默認(rèn)測(cè)試運(yùn)行程序。

注意:如果您的測(cè)試套件依賴于 JUnit3 和 JUnit4 庫(kù)的混合搭配,請(qǐng)?jiān)跍y(cè)試類定義的開(kāi)頭添加 @RunWith(AndroidJUnit4::class) 注釋。

以下示例展示了如何編寫(xiě)插樁單元測(cè)試來(lái)驗(yàn)證是否為 LogHistory 類正確實(shí)現(xiàn)了 Parcelable 接口:

 

import android.os.Parcel import android.text.TextUtils.writeToParcel import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith const val TEST_STRING = "This is a string" const val TEST_LONG = 12345678L // @RunWith is required only if you use a mix of JUnit3 and JUnit4. @RunWith(AndroidJUnit4::class) @SmallTest class LogHistoryAndroidUnitTest { private lateinit var logHistory: LogHistory @Before fun createLogHistory() { logHistory = LogHistory() } @Test fun logHistory_ParcelableWriteRead() { val parcel = Parcel.obtain() logHistory.apply { // Set up the Parcelable object to send and receive. addEntry(TEST_STRING, TEST_LONG) // Write the data. writeToParcel(parcel, describeContents()) } // After you're done with writing, you need to reset the parcel for reading. parcel.setDataPosition(0) // Read the data. val createdFromParcel: LogHistory = LogHistory.CREATOR.createFromParcel(parcel) createdFromParcel.getData().also { createdFromParcelData: List<Pair<String, Long>> -> // Verify that the received data is correct. assertThat(createdFromParcelData.size).isEqualTo(1) assertThat(createdFromParcelData[0].first).isEqualTo(TEST_STRING) assertThat(createdFromParcelData[0].second).isEqualTo(TEST_LONG) } } }

創(chuàng)建測(cè)試套件

為了使插樁單元測(cè)試的執(zhí)行有條不紊,您可以將一系列測(cè)試類歸入一個(gè)測(cè)試套件類,并將這些測(cè)試一起運(yùn)行。測(cè)試套件可以嵌套;您的測(cè)試套件可以將其他測(cè)試套件歸在一起,并將其所有組件測(cè)試類一起運(yùn)行。

測(cè)試套件包含在測(cè)試軟件包中,類似于主應(yīng)用軟件包。按照慣例,測(cè)試套件軟件包名稱通常以 .suite 后綴結(jié)尾(例如,com.example.android.testing.mysample.suite)。

如需為您的單元測(cè)試創(chuàng)建測(cè)試套件,請(qǐng)導(dǎo)入 JUnit RunWithSuite 類。在您的測(cè)試套件中,添加 @RunWith(Suite.class)@Suite.SuitClasses() 注釋。在 @Suite.SuiteClasses() 注釋中,將各個(gè)測(cè)試類或測(cè)試套件作為參數(shù)列出。

以下示例展示了如何實(shí)現(xiàn)名為UnitTestSuite的測(cè)試套件,該測(cè)試套件將CalculatorInstrumentationTestCalculatorAddParameterizedTest測(cè)試類組合在一起并運(yùn)行。

 

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) class UnitTestSuite

利用 Firebase 測(cè)試實(shí)驗(yàn)室運(yùn)行測(cè)試

使用 Firebase 測(cè)試實(shí)驗(yàn)室,您可以同時(shí)在許多主流 Android 設(shè)備和設(shè)備配置(語(yǔ)言區(qū)域、屏幕方向、屏幕尺寸和平臺(tái)版本)上測(cè)試您的應(yīng)用。這些測(cè)試在遠(yuǎn)程 Google 數(shù)據(jù)中心的物理設(shè)備和虛擬設(shè)備上運(yùn)行。您可以直接通過(guò) Android Studio 或從命令行將應(yīng)用部署到測(cè)試實(shí)驗(yàn)室。測(cè)試結(jié)果會(huì)提供測(cè)試日志,并包含所有應(yīng)用故障的詳細(xì)信息。

在開(kāi)始使用 Firebase 測(cè)試實(shí)驗(yàn)室之前,除非您已經(jīng)擁有 Google 帳號(hào)和 Firebase 項(xiàng)目,否則您需要執(zhí)行以下操作:

  1. 創(chuàng)建一個(gè) Google 帳號(hào)(如果您還沒(méi)有帳號(hào))。

  2. 在 Firebase 控制臺(tái)中,點(diǎn)擊新建項(xiàng)目。

  3. 利用測(cè)試實(shí)驗(yàn)室在 Spark 方案每日免費(fèi)配額內(nèi)測(cè)試您的應(yīng)用時(shí)不收取任何費(fèi)用。

三、自動(dòng)執(zhí)行界面測(cè)試

通過(guò)界面測(cè)試,您可以確保應(yīng)用滿足其功能要求并達(dá)到較高的質(zhì)量標(biāo)準(zhǔn),從而更有可能成功地被用戶采用。

界面測(cè)試的一種方法是直接讓測(cè)試人員對(duì)目標(biāo)應(yīng)用執(zhí)行一系列用戶操作,并驗(yàn)證其行為是否正常。不過(guò),這種人工方法會(huì)非常耗時(shí)、繁瑣且容易出錯(cuò)。一種更高效的方法是編寫(xiě)界面測(cè)試,以便以自動(dòng)化方式執(zhí)行用戶操作。自動(dòng)化方法可讓您以可重復(fù)的方式快速可靠地運(yùn)行測(cè)試。

如需使用 Android Studio 自動(dòng)執(zhí)行界面測(cè)試,請(qǐng)?jiān)趩为?dú)的 Android 測(cè)試文件夾 (src/androidTest/java) 中實(shí)現(xiàn)測(cè)試代碼。Android Plugin for Gradle 會(huì)根據(jù)測(cè)試代碼構(gòu)建一個(gè)測(cè)試應(yīng)用,然后在目標(biāo)應(yīng)用所在的設(shè)備上加載該測(cè)試應(yīng)用。在測(cè)試代碼中,您可以使用界面測(cè)試框架來(lái)模擬目標(biāo)應(yīng)用上的用戶交互,以便執(zhí)行涵蓋特定使用場(chǎng)景的測(cè)試任務(wù)。

為了測(cè)試 Android 應(yīng)用,您通常會(huì)創(chuàng)建下面這些類型的自動(dòng)化界面測(cè)試:

  • 涵蓋單個(gè)應(yīng)用的界面測(cè)試:這種類型的測(cè)試可驗(yàn)證目標(biāo)應(yīng)用在用戶執(zhí)行特定操作或在其 Activity 中輸入特定內(nèi)容時(shí)的行為是否符合預(yù)期。它可讓您檢查目標(biāo)應(yīng)用是否返回正確的界面輸出來(lái)響應(yīng)應(yīng)用 Activity 中的用戶交互。諸如 Espresso 之類的界面測(cè)試框架可讓您以編程方式模擬用戶操作,并測(cè)試復(fù)雜的應(yīng)用內(nèi)用戶交互。

  • 涵蓋多個(gè)應(yīng)用的界面測(cè)試:這種類型的測(cè)試可驗(yàn)證不同用戶應(yīng)用之間交互或用戶應(yīng)用與系統(tǒng)應(yīng)用之間交互的正確行為。例如,您可能想要測(cè)試相機(jī)應(yīng)用是否能夠與第三方社交媒體應(yīng)用或默認(rèn)的 Android 相冊(cè)應(yīng)用正確分享圖片。支持跨應(yīng)用交互的界面測(cè)試框架(如 UI Automator)可讓您針對(duì)此類場(chǎng)景創(chuàng)建測(cè)試。

測(cè)試單個(gè)應(yīng)用的界面

測(cè)試單個(gè)應(yīng)用內(nèi)的用戶交互有助于確保用戶在與應(yīng)用交互時(shí)不會(huì)遇到意外結(jié)果或體驗(yàn)不佳的情況。如果您需要驗(yàn)證應(yīng)用的界面是否正常運(yùn)行,應(yīng)養(yǎng)成創(chuàng)建界面測(cè)試的習(xí)慣。

由 AndroidX Test 提供的 Espresso 測(cè)試框架提供了一些 API,用于編寫(xiě)界面測(cè)試以模擬單個(gè)目標(biāo)應(yīng)用內(nèi)的用戶交互。Espresso 測(cè)試可以在搭載 Android 2.3.3(API 級(jí)別 10)及更高版本的設(shè)備上運(yùn)行。使用 Espresso 的主要好處在于,它可以自動(dòng)同步測(cè)試操作與您正在測(cè)試的應(yīng)用的界面。Espresso 會(huì)檢測(cè)主線程何時(shí)處于空閑狀態(tài),以便可以在適當(dāng)?shù)臅r(shí)間運(yùn)行測(cè)試命令,從而提高測(cè)試的可靠性。此外,借助該功能,您不必在測(cè)試代碼中添加任何計(jì)時(shí)解決方法,如 Thread.sleep()。

Espresso 測(cè)試框架是基于插樁的 API,可與 AndroidJUnitRunner 測(cè)試運(yùn)行程序一起使用

設(shè)置 Espresso

在使用 Espresso 構(gòu)建界面測(cè)試之前,請(qǐng)務(wù)必設(shè)置對(duì) Espresso 庫(kù)的依賴項(xiàng)引用:

 

dependencies { androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' }

在測(cè)試設(shè)備上關(guān)閉動(dòng)畫(huà) - 如果讓系統(tǒng)動(dòng)畫(huà)在測(cè)試設(shè)備上保持開(kāi)啟狀態(tài),可能會(huì)導(dǎo)致意外結(jié)果或?qū)е聹y(cè)試失敗。通過(guò)以下方式關(guān)閉動(dòng)畫(huà):在“設(shè)置”中打開(kāi)“開(kāi)發(fā)者選項(xiàng)”,然后關(guān)閉以下所有選項(xiàng):

  • 窗口動(dòng)畫(huà)縮放

  • 過(guò)渡動(dòng)畫(huà)縮放

  • Animator 時(shí)長(zhǎng)縮放

創(chuàng)建 Espresso 測(cè)試類、

如需創(chuàng)建 Espresso 測(cè)試,請(qǐng)遵循以下編程模型:

  1. 通過(guò)調(diào)用 onView() 方法或 AdapterView 控件的 onData() 方法,在 Activity 中找到要測(cè)試的界面組件(例如,應(yīng)用中的登錄按鈕)。

  2. 通過(guò)調(diào)用 ViewInteraction.perform()DataInteraction.perform()方法并傳入用戶操作(例如,點(diǎn)擊登錄按鈕),模擬要在該界面組件上執(zhí)行的特定用戶交互。如需對(duì)同一界面組件上的多項(xiàng)操作進(jìn)行排序,請(qǐng)?jiān)诜椒▍?shù)中使用逗號(hào)分隔列表將它們鏈接起來(lái)。

  3. 根據(jù)需要重復(fù)上述步驟,以模擬目標(biāo)應(yīng)用中跨多個(gè) Activity 的用戶流。

  4. 執(zhí)行這些用戶交互后,使用 ViewAssertions 方法檢查界面是否反映了預(yù)期的狀態(tài)或行為。

下面幾部分更詳細(xì)地介紹了這些步驟。

以下代碼段展示了測(cè)試類如何調(diào)用此基本工作流程:

 

onView(withId(R.id.my_view)) // withId(R.id.my_view) is a ViewMatcher .perform(click()) // click() is a ViewAction .check(matches(isDisplayed())) // matches(isDisplayed()) is a ViewAssertion

將 Espresso 與 ActivityTestRule 一起使用

下文介紹如何創(chuàng)建新的 JUnit 4 型 Espresso 測(cè)試,并使用 ActivityTestRule 減少您需要編寫(xiě)的樣板代碼量。通過(guò)使用 ActivityTestRule,測(cè)試框架會(huì)在帶有 @Test 注釋的每個(gè)測(cè)試方法運(yùn)行之前以及帶有 @Before 注釋的所有方法運(yùn)行之前啟動(dòng)被測(cè) Activity。該框架將在測(cè)試完成并且?guī)в?@After 注釋的所有方法都運(yùn)行后關(guān)閉該 Activity。

 

package com.example.android.testing.espresso.BasicSample import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import androidx.test.rule.ActivityTestRule import androidx.test.runner.AndroidJUnit4 @RunWith(AndroidJUnit4::class) @LargeTest class ChangeTextBehaviorTest { private lateinit var stringToBetyped: String @get:Rule var activityRule: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java) @Before fun initValidString() { // Specify a valid string. stringToBetyped = "Espresso" } @Test fun changeText_sameActivity() { // Type text and then press the button. onView(withId(R.id.editTextUserInput)) .perform(typeText(stringToBetyped), closeSoftKeyboard()) onView(withId(R.id.changeTextBt)).perform(click()) // Check that the text was changed. onView(withId(R.id.textToBeChanged)) .check(matches(withText(stringToBetyped))) } }

訪問(wèn)界面組件

您必須先指定界面組件或視圖,然后 Espresso 才能與被測(cè)應(yīng)用進(jìn)行交互。Espresso 支持使用 Hamcrest 匹配器指定應(yīng)用中的視圖和適配器。

如需查看視圖,請(qǐng)調(diào)用 onView() 方法并傳入用于指定目標(biāo)視圖的視圖匹配器。指定視圖匹配器部分對(duì)此進(jìn)行了更詳細(xì)的說(shuō)明。onView() 方法將返回一個(gè) ViewInteraction 對(duì)象,該對(duì)象允許測(cè)試與視圖進(jìn)行交互。但是,如果希望在 RecyclerView 布局中查找視圖,調(diào)用 onView() 方法可能不起作用。在這種情況下,請(qǐng)按照在 AdapterView 中查找視圖中的說(shuō)明進(jìn)行操作。

以下代碼段展示了如何編寫(xiě)一個(gè)先訪問(wèn) EditText 字段,再輸入文本字符串,接著關(guān)閉虛擬鍵盤(pán),然后執(zhí)行按鈕點(diǎn)擊操作的測(cè)試。

 

fun testChangeText_sameActivity() { // Type text and then press the button. onView(withId(R.id.editTextUserInput)) .perform(typeText(STRING_TO_BE_TYPED), closeSoftKeyboard()) onView(withId(R.id.changeTextButton)).perform(click()) // Check that the text was changed. ... }

指定視圖匹配器

您可以使用以下方法指定視圖匹配器:

  • 調(diào)用 ViewMatchers 類中的方法。例如,如需通過(guò)查找視圖顯示的文本字符串查找視圖,您可以調(diào)用以下方法:

 

onView(withText("Sign-in"))

同樣,您可以調(diào)用 withId() 并提供視圖的資源 ID (R.id),如以下示例所示:

 

onView(withId(R.id.button_signin))

  • 不能保證 Android 資源 ID 是唯一的。如果測(cè)試嘗試匹配由多個(gè)視圖使用的某個(gè)資源 ID,Espresso 會(huì)拋出 AmbiguousViewMatcherException。

  • 使用 Matchers 類。您可以使用 allOf() 方法組合多個(gè)匹配器,例如 containsString()instanceOf()。此方法可讓您更精細(xì)地過(guò)濾匹配結(jié)果,如以下示例所示:

 

onView(allOf(withId(R.id.button_signin), withText("Sign-in")))

您可以使用 not 關(guān)鍵字過(guò)濾與匹配器不對(duì)應(yīng)的視圖,如以下示例所示:

 

onView(allOf(withId(R.id.button_signin), not(withText("Sign-out"))))

如需在測(cè)試中使用這些方法,請(qǐng)導(dǎo)入 org.hamcrest.Matchers 軟件包。如需詳細(xì)了解 Hamcrest 匹配,請(qǐng)?jiān)L問(wèn) Hamcrest 網(wǎng)站。

如需提高 Espresso 測(cè)試的性能,請(qǐng)指定查找目標(biāo)視圖所需的最少匹配信息。例如,如果某個(gè)視圖可通過(guò)其描述性文本進(jìn)行唯一標(biāo)識(shí),您無(wú)需指定該視圖也可從 TextView 實(shí)例分配。

在 AdapterView 中查找視圖

AdapterView 微件中,視圖會(huì)在運(yùn)行時(shí)由子視圖動(dòng)態(tài)填充。如果您要測(cè)試的目標(biāo)視圖位于 AdapterView(例如 ListView、GridViewSpinner)內(nèi),則 onView() 方法可能不起作用,因?yàn)橹荒軐⒁徊糠忠晥D加載到當(dāng)前視圖層次結(jié)構(gòu)中。

應(yīng)改為調(diào)用 onData()方法獲取 DataInteraction 對(duì)象,以訪問(wèn)目標(biāo)視圖元素。Espresso 負(fù)責(zé)將目標(biāo)視圖元素加載到當(dāng)前視圖層次結(jié)構(gòu)中。Espresso 還負(fù)責(zé)滾動(dòng)到目標(biāo)元素,并將該元素置于焦點(diǎn)上。

注意onData() 方法不檢查您指定的項(xiàng)是否與視圖對(duì)應(yīng)。Espresso 僅搜索當(dāng)前視圖層次結(jié)構(gòu)。如果未找到匹配項(xiàng),該方法會(huì)拋出 NoMatchingViewException

以下代碼段展示了如何結(jié)合使用 onData() 方法和 Hamcrest 匹配搜索列表中包含給定字符串的特定行。在本例中,LongListActivity 類包含通過(guò) SimpleAdapter 公開(kāi)的字符串列表。

 

onData(allOf(`is`(instanceOf(Map::class.java)), hasEntry(equalTo(LongListActivity.ROW_TEXT), `is`("test input"))))

執(zhí)行操作

調(diào)用 ViewInteraction.perform()DataInteraction.perform() 方法,以模擬界面組件上的用戶交互。您必須將一個(gè)或多個(gè) ViewAction 對(duì)象作為參數(shù)傳入。Espresso 將按照給定的順序依次觸發(fā)每項(xiàng)操作,并在主線程中執(zhí)行這些操作。

ViewActions 類提供了用于指定常見(jiàn)操作的輔助程序方法的列表。您可以將這些方法用作方便的快捷方式,而不是創(chuàng)建和配置單個(gè) ViewAction 對(duì)象。您可以指定以下操作:

  • ViewActions.click():點(diǎn)擊視圖。

  • ViewActions.typeText():點(diǎn)擊視圖并輸入指定的字符串。

  • ViewActions.scrollTo():滾動(dòng)到視圖。目標(biāo)視圖必須是由 ScrollView 派生的子類,并且其 android:visibility 屬性的值必須為 VISIBLE。對(duì)于擴(kuò)展 AdapterView 的視圖(例如 ListView),onData() 方法將負(fù)責(zé)為您滾動(dòng)。

  • ViewActions.pressKey():使用指定的鍵碼執(zhí)行按鍵操作。

  • ViewActions.clearText():清除目標(biāo)視圖中的文本。

如果目標(biāo)視圖位于 ScrollView 內(nèi),請(qǐng)先執(zhí)行 ViewActions.scrollTo() 操作以在屏幕中顯示該視圖,然后再繼續(xù)執(zhí)行其他操作。如果已顯示該視圖,則 ViewActions.scrollTo() 操作將不起作用。

使用 Espresso Intent 單獨(dú)測(cè)試 Activity

Espresso Intent 支持對(duì)應(yīng)用發(fā)出的 intent 進(jìn)行驗(yàn)證和打樁。使用 Espresso Intent,您可以通過(guò)以下方式單獨(dú)測(cè)試應(yīng)用、Activity 或服務(wù):攔截傳出 intent,對(duì)結(jié)果進(jìn)行打樁,然后將其發(fā)送回被測(cè)組件。

如需開(kāi)始使用 Espresso Intent 進(jìn)行測(cè)試,您需要將以下代碼行添加到應(yīng)用的 build.gradle 文件中:

 

dependencies { androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.0' }

如需測(cè)試 intent,您需要?jiǎng)?chuàng)建 IntentsTestRule 類(與 ActivityTestRule 類非常相似)的實(shí)例。IntentsTestRule 類會(huì)在每次測(cè)試前初始化 Espresso Intent,終止托管 Activity,并在每次測(cè)試后釋放 Espresso Intent。

以下代碼段中顯示的測(cè)試類提供了顯式 intent 的簡(jiǎn)單測(cè)試。

 

private const val MESSAGE = "This is a test" private const val PACKAGE_NAME = "com.example.myfirstapp" @RunWith(AndroidJUnit4::class) class SimpleIntentTest { /* Instantiate an IntentsTestRule object. */ @get:Rule var intentsRule: IntentsTestRule<MainActivity> = IntentsTestRule(MainActivity::class.java) @Test fun verifyMessageSentToMessageActivity() { // Types a message into a EditText element. onView(withId(R.id.edit_message)) .perform(typeText(MESSAGE), closeSoftKeyboard()) // Clicks a button to send the message to another // activity through an explicit intent. onView(withId(R.id.send_message)).perform(click()) // Verifies that the DisplayMessageActivity received an intent // with the correct package name and message. intended(allOf( hasComponent(hasShortClassName(".DisplayMessageActivity")), toPackage(PACKAGE_NAME), hasExtra(MainActivity.EXTRA_MESSAGE, MESSAGE))) } }

使用 Espresso Web 測(cè)試 WebView

使用 Espresso Web,您可以測(cè)試包含在 Activity 中的 WebView 組件。它使用 WebDriver API 檢查和控制 WebView 的行為。

如需開(kāi)始使用 Espresso Web 進(jìn)行測(cè)試,您需要將以下代碼行添加到應(yīng)用的 build.gradle 文件中:

 

dependencies { androidTestImplementation 'androidx.test.espresso:espresso-web:3.1.0' }

在使用 Espresso Web 創(chuàng)建測(cè)試的過(guò)程中,當(dāng)您實(shí)例化 ActivityTestRule 對(duì)象以測(cè)試 Activity 時(shí),需要在 WebView 上啟用 JavaScript。在測(cè)試中,您可以選擇 WebView 中顯示的 HTML 元素并模擬用戶交互,例如在文本框中輸入文本,然后點(diǎn)擊某個(gè)按鈕。完成這些操作后,您可以驗(yàn)證網(wǎng)頁(yè)上的結(jié)果是否與預(yù)期結(jié)果一致。

以下代碼段中,該類測(cè)試被測(cè) Activity 中 ID 值為“webview”的 WebView 組件。typeTextInInput_clickButton_SubmitsForm() 測(cè)試先選擇網(wǎng)頁(yè)上的一個(gè) <input> 元素,再輸入一些文本,然后檢查出現(xiàn)在另一個(gè)元素中的文本。

 

private const val MACCHIATO = "Macchiato" private const val DOPPIO = "Doppio" @LargeTest @RunWith(AndroidJUnit4::class) class WebViewActivityTest { @get:Rule val activityRule = object : ActivityTestRule<WebViewActivity>( WebViewActivity::class.java, false, /* Initial touch mode */ false /* launch activity */ ) { override fun afterActivityLaunched() { // Enable JavaScript. onWebView().forceJavascriptEnabled() } } @Test fun typeTextInInput_clickButton_SubmitsForm() { // Lazily launch the Activity with a custom start Intent per test activityRule.launchActivity(withWebFormIntent()) // Selects the WebView in your layout. // If you have multiple WebViews you can also use a // matcher to select a given WebView, onWebView(withId(R.id.web_view)). onWebView() // Find the input element by ID .withElement(findElement(Locator.ID, "text_input")) // Clear previous input .perform(clearElement()) // Enter text into the input element .perform(DriverAtoms.webKeys(MACCHIATO)) // Find the submit button .withElement(findElement(Locator.ID, "submitBtn")) // Simulate a click via JavaScript .perform(webClick()) // Find the response element by ID .withElement(findElement(Locator.ID, "response")) // Verify that the response page contains the entered text .check(webMatches(getText(), containsString(MACCHIATO))) } }

驗(yàn)證結(jié)果

調(diào)用 ViewInteraction.check()DataInteraction.check() 方法以斷言界面中的視圖與某種預(yù)期狀態(tài)匹配。您必須將 ViewAssertion 對(duì)象作為參數(shù)傳入。如果斷言失敗,Espresso 會(huì)拋出 AssertionFailedError。

ViewAssertions 類提供了用于指定常見(jiàn)斷言的輔助程序方法的列表??梢允褂玫臄嘌园ǎ?/p>

  • doesNotExist:斷言當(dāng)前視圖層次結(jié)構(gòu)中沒(méi)有符合指定條件的視圖。

  • matches:斷言當(dāng)前視圖層次結(jié)構(gòu)中存在指定的視圖,并且其狀態(tài)與某個(gè)給定的 Hamcrst 匹配器匹配。

  • selectedDescendentsMatch:斷言存在父視圖的指定子視圖,并且其狀態(tài)與某個(gè)給定的 Hamcrst 匹配器匹配。

以下代碼段展示了如何檢查界面中顯示的文本與先前在 EditText 字段中輸入的文本是否具有相同的值。

 

fun testChangeText_sameActivity() { // Type text and then press the button. ... // Check that the text was changed. onView(withId(R.id.textToBeChanged)) .check(matches(withText(STRING_TO_BE_TYPED))) }

測(cè)試多個(gè)應(yīng)用的界面

通過(guò)涉及多個(gè)應(yīng)用中的用戶交互的界面測(cè)試,您可以驗(yàn)證當(dāng)用戶流跨入其他應(yīng)用或系統(tǒng)界面時(shí),您的應(yīng)用是否能夠正常運(yùn)行。短信應(yīng)用就是此類用戶流的一個(gè)例子,該應(yīng)用先讓用戶輸入短信,再啟動(dòng) Android 聯(lián)系人選擇器,以便用戶可以選擇短信的收件人,然后將控制權(quán)返還給原來(lái)的應(yīng)用,以便用戶提交短信。

本課介紹如何使用 AndroidX Test 提供的 UI Automator 測(cè)試框架來(lái)編寫(xiě)此類界面測(cè)試。通過(guò) UI Automator API,您可以與設(shè)備上的可見(jiàn)元素進(jìn)行交互,而不管焦點(diǎn)在哪個(gè) Activity 上。您的測(cè)試可以使用方便的描述符(如顯示在相應(yīng)組件中的文本或其內(nèi)容描述)來(lái)查找界面組件。UI Automator 測(cè)試可以在搭載 Android 4.3(API 級(jí)別 18)或更高版本的設(shè)備上運(yùn)行。

UI Automator 測(cè)試框架是基于插樁的 API,可與 AndroidJUnitRunner 測(cè)試運(yùn)行程序一起使用。

設(shè)置 UI Automator

在使用 UI Automator 構(gòu)建界面測(cè)試之前,請(qǐng)務(wù)必配置測(cè)試源代碼位置和項(xiàng)目依賴項(xiàng),如針對(duì) AndroidX Test 設(shè)置項(xiàng)目中所述。

在 Android 應(yīng)用模塊的 build.gradle 文件中,您必須設(shè)置對(duì) UI Automator 庫(kù)的依賴項(xiàng)引用:

 

dependencies { ... androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' }

要優(yōu)化 UI Automator 測(cè)試,您應(yīng)先檢查目標(biāo)應(yīng)用的界面組件并確保它們可訪問(wèn)。這些優(yōu)化提示將在接下來(lái)的兩部分中進(jìn)行介紹。

創(chuàng)建 UI Automator 測(cè)試類

UI Automator 測(cè)試類的編寫(xiě)方式應(yīng)與 JUnit 4 測(cè)試類相同。

在測(cè)試類定義的開(kāi)頭添加 @RunWith(AndroidJUnit4.class) 注釋。您還需要將 AndroidX Test 中提供的 AndroidJUnitRunner 類指定為默認(rèn)測(cè)試運(yùn)行程序。

在 UI Automator 測(cè)試類中實(shí)現(xiàn)以下編程模型:

  1. 通過(guò)調(diào)用 getInstance() 方法并將 Instrumentation 對(duì)象作為參數(shù)傳遞給該方法,獲取 UiDevice 對(duì)象以訪問(wèn)要測(cè)試的設(shè)備。

  2. 通過(guò)調(diào)用 findObject() 方法,獲取 UiObject 對(duì)象以訪問(wèn)設(shè)備上顯示的界面組件(例如,前臺(tái)的當(dāng)前視圖)。

  3. 通過(guò)調(diào)用 UiObject 方法,模擬需要在該界面組件上執(zhí)行的特定用戶交互;例如,調(diào)用 performMultiPointerGesture() 以模擬多點(diǎn)觸控手勢(shì),以及調(diào)用 setText() 以修改文本字段。您可以根據(jù)需要反復(fù)調(diào)用第 2 步和第 3 步中的 API,以測(cè)試涉及多個(gè)界面組件或用戶操作序列的更復(fù)雜的用戶交互。

  4. 執(zhí)行這些用戶交互后,檢查界面是否反映了預(yù)期的狀態(tài)或行為。

下面幾部分更詳細(xì)地介紹了這些步驟。

訪問(wèn)界面組件

UiDevice 對(duì)象是您訪問(wèn)和操縱設(shè)備狀態(tài)的主要方式。在測(cè)試中,您可以調(diào)用 UiDevice 方法檢查各種屬性的狀態(tài),如當(dāng)前屏幕方向或顯示屏尺寸。您的測(cè)試可以使用 UiDevice 對(duì)象執(zhí)行設(shè)備級(jí)操作,如強(qiáng)制設(shè)備進(jìn)行特定旋轉(zhuǎn)、按方向鍵硬件按鈕,以及按主屏幕和菜單按鈕。

最好從設(shè)備的主屏幕開(kāi)始測(cè)試。在主屏幕(或您在設(shè)備中選擇的其他某個(gè)起始位置)上,您可以調(diào)用 UI Automator API 提供的方法,以選擇特定的界面元素并與之交互。

以下代碼段展示了您的測(cè)試如何獲取 UiDevice 實(shí)例并模擬按主屏幕按鈕的操作:

 

import org.junit.Before import androidx.test.runner.AndroidJUnit4 import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.By import androidx.test.uiautomator.Until ... private const val BASIC_SAMPLE_PACKAGE = "com.example.android.testing.uiautomator.BasicSample" private const val LAUNCH_TIMEOUT = 5000L private const val STRING_TO_BE_TYPED = "UiAutomator" @RunWith(AndroidJUnit4::class) @SdkSuppress(minSdkVersion = 18) class ChangeTextBehaviorTest2 { private lateinit var device: UiDevice @Before fun startMainActivityFromHomeScreen() { // Initialize UiDevice instance device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) // Start from the home screen device.pressHome() // Wait for launcher val launcherPackage: String = device.launcherPackageName assertThat(launcherPackage, notNullValue()) device.wait( Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT ) // Launch the app val context = ApplicationProvider.getApplicationContext<Context>() val intent = context.packageManager.getLaunchIntentForPackage( BASIC_SAMPLE_PACKAGE).apply { // Clear out any previous instances addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) } context.startActivity(intent) // Wait for the app to appear device.wait( Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)), LAUNCH_TIMEOUT ) } }

使用 findObject() 方法檢索 UiObject,它表示符合給定選擇器條件的視圖。您可以根據(jù)需要重復(fù)使用已在應(yīng)用測(cè)試的其他部分中創(chuàng)建的 UiObject 實(shí)例。請(qǐng)注意,每當(dāng)您的測(cè)試使用 UiObject 實(shí)例以點(diǎn)擊界面元素或查詢屬性時(shí),UI Automator 測(cè)試框架都會(huì)在當(dāng)前顯示內(nèi)容中搜索匹配項(xiàng)。

以下代碼段展示了您的測(cè)試如何構(gòu)建表示應(yīng)用中的“取消”按鈕和“確定”按鈕的 UiObject 實(shí)例。

 

val cancelButton: UiObject = device.findObject( UiSelector().text("Cancel").className("android.widget.Button") ) val okButton: UiObject = device.findObject( UiSelector().text("OK").className("android.widget.Button") ) // Simulate a user-click on the OK button, if found. if (okButton.exists() && okButton.isEnabled) { okButton.click() }

指定選擇器

如果您需要訪問(wèn)應(yīng)用中的特定界面組件,請(qǐng)使用 UiSelector 類。此類表示對(duì)當(dāng)前顯示的界面中特定元素的查詢。

如果找到了多個(gè)匹配元素,系統(tǒng)會(huì)將布局層次結(jié)構(gòu)中的第一個(gè)匹配元素作為目標(biāo) UiObject 返回。構(gòu)建 UiSelector 時(shí),您可以將多個(gè)屬性鏈接在一起以優(yōu)化搜索。如果未找到匹配的界面元素,系統(tǒng)會(huì)拋出 UiAutomatorObjectNotFoundException。

您可以使用 childSelector() 方法來(lái)嵌套多個(gè) UiSelector 個(gè)實(shí)例。例如,以下代碼示例展示了您的測(cè)試如何指定搜索,以在當(dāng)前顯示的界面中查找第一個(gè) ListView,然后在該 ListView 中搜索,以查找具有文本屬性“Apps”的界面元素。

 

val appItem: UiObject = device.findObject( UiSelector().className("android.widget.ListView") .instance(0) .childSelector( UiSelector().text("Apps") ) )

最佳做法是,在指定選擇器時(shí),應(yīng)使用資源 ID(如果已將其分配給界面元素),而不是文本元素或內(nèi)容描述符。并非所有元素都有文本元素(例如,工具欄中的圖標(biāo))。文本選擇器很脆弱,如果界面發(fā)生細(xì)微更改,可能會(huì)導(dǎo)致測(cè)試失敗。此外,文本選擇器也可能無(wú)法在不同語(yǔ)言之間擴(kuò)展,它們可能與翻譯的字符串不匹配。

在選擇器條件中指定對(duì)象狀態(tài)可能很有用。例如,如果要選擇所有已選中元素的列表以便取消選中這些元素,請(qǐng)調(diào)用 checked() 方法并將參數(shù)設(shè)置為 true

執(zhí)行操作

您的測(cè)試獲取 UiObject 對(duì)象后,您可以調(diào)用 UiObject 類中的方法,在由該對(duì)象表示的界面組件上執(zhí)行用戶交互。您可以指定如下操作:

  • click():點(diǎn)擊界面元素的可見(jiàn)邊界的中心。

  • dragTo():將此對(duì)象拖動(dòng)到任意坐標(biāo)。

  • setText():清除可修改字段的內(nèi)容后,設(shè)置該字段中的文本。相反,clearTextField() 方法用于清除可修改字段中的現(xiàn)有文本。

  • swipeUp():對(duì) UiObject 執(zhí)行向上滑動(dòng)操作。同樣,swipeDown()、swipeLeft()swipeRight() 方法用于執(zhí)行相應(yīng)的操作。

通過(guò) UI Automator 測(cè)試框架,您可以發(fā)送 Intent 或啟動(dòng) Activity,無(wú)需使用 shell 命令,只需通過(guò) getContext() 獲取 Context 對(duì)象即可。

以下代碼段展示了您的測(cè)試如何使用 Intent 啟動(dòng)被測(cè)應(yīng)用。當(dāng)您只想測(cè)試計(jì)算器應(yīng)用而不關(guān)心啟動(dòng)器時(shí),此方法很有用。

 

fun setUp() { ... // Launch a simple calculator app val context = getInstrumentation().context val intent = context.packageManager.getLaunchIntentForPackage(CALC_PACKAGE).apply { addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) } // Clear out any previous instances context.startActivity(intent) device.wait(Until.hasObject(By.pkg(CALC_PACKAGE).depth(0)), TIMEOUT) }

對(duì)集合執(zhí)行操作

如果需要模擬內(nèi)容集合(例如,音樂(lè)專輯中的歌曲或收件箱中的電子郵件列表)上的用戶交互,請(qǐng)使用 UiCollection 類。要?jiǎng)?chuàng)建 UiCollection 對(duì)象,請(qǐng)指定 UiSelector,用于搜索其他子界面元素的界面容器或封裝容器,如包含子界面元素的布局視圖。

以下代碼段展示了您的測(cè)試如何構(gòu)建 UiCollection 以表示 FrameLayout 中顯示的視頻專輯:

 

val videos = UiCollection(UiSelector().className("android.widget.FrameLayout")) // Retrieve the number of videos in this collection: val count = videos.getChildCount( UiSelector().className("android.widget.LinearLayout") ) // Find a specific video and simulate a user-click on it val video: UiObject = videos.getChildByText( UiSelector().className("android.widget.LinearLayout"), "Cute Baby Laughing" ) video.click() // Simulate selecting a checkbox that is associated with the video val checkBox: UiObject = video.getChild( UiSelector().className("android.widget.Checkbox") ) if (!checkBox.isSelected) checkBox.click()

對(duì)可滾動(dòng)視圖執(zhí)行操作

使用 UiScrollable 類模擬顯示屏上的垂直或水平滾動(dòng)。當(dāng)界面元素位于屏幕外而您需要滾動(dòng)屏幕以使其進(jìn)入視野時(shí),此方法很有用。

以下代碼段展示了如何模擬向下滾動(dòng)“設(shè)置”菜單并點(diǎn)擊“關(guān)于平板電腦”選項(xiàng)的操作:

 

val settingsItem = UiScrollable(UiSelector().className("android.widget.ListView")) val about: UiObject = settingsItem.getChildByText( UiSelector().className("android.widget.LinearLayout"), "About tablet" ) about.click()

驗(yàn)證結(jié)果

InstrumentationTestCase 擴(kuò)展了 TestCase,因此您可以使用標(biāo)準(zhǔn)的 JUnit Assert 方法測(cè)試應(yīng)用中的界面組件是否會(huì)返回預(yù)期結(jié)果。

以下代碼段展示了您的測(cè)試如何找到計(jì)算器應(yīng)用中的幾個(gè)按鈕,按順序點(diǎn)擊它們,然后驗(yàn)證是否顯示了正確的結(jié)果。

 

private const val CALC_PACKAGE = "com.myexample.calc" fun testTwoPlusThreeEqualsFive() { // Enter an equation: 2 + 3 = ? device.findObject(UiSelector().packageName(CALC_PACKAGE).resourceId("two")).click() device.findObject(UiSelector().packageName(CALC_PACKAGE).resourceId("plus")).click() device.findObject(UiSelector().packageName(CALC_PACKAGE).resourceId("three")).click() device.findObject(UiSelector().packageName(CALC_PACKAGE).resourceId("equals")).click() // Verify the result = 5 val result: UiObject2 = device.findObject(By.res(CALC_PACKAGE, "result")) assertEquals("5", result.text) }

四、測(cè)試應(yīng)用組件集成

如果您的應(yīng)用使用了用戶不直接與之互動(dòng)的組件(如服務(wù)或內(nèi)容提供器),您應(yīng)驗(yàn)證這些組件在應(yīng)用中的行為方式是否正確。

在開(kāi)發(fā)此類組件時(shí),您應(yīng)養(yǎng)成編寫(xiě)集成測(cè)試的習(xí)慣,以便當(dāng)您的應(yīng)用在設(shè)備或模擬器上運(yùn)行時(shí)驗(yàn)證組件的行為。

注意:Android 不為 BroadcastReceiver 提供單獨(dú)的測(cè)試用例類。如需驗(yàn)證 BroadcastReceiver 是否正確響應(yīng),您可以測(cè)試向其發(fā)送 Intent 對(duì)象的組件。或者,您可以通過(guò)調(diào)用 ApplicationProvider.getApplicationContext() 來(lái)創(chuàng)建 BroadcastReceiver 的實(shí)例,然后調(diào)用要測(cè)試的 BroadcastReceiver 方法(通常,這是 onReceive() 方法)。

測(cè)試服務(wù)

如果您要實(shí)現(xiàn)將本地 Service 作為應(yīng)用的組件,則應(yīng)對(duì) Service 進(jìn)行測(cè)試,以確保其不會(huì)出現(xiàn)意外行為。您可以創(chuàng)建插樁單元測(cè)試以驗(yàn)證 Service 的行為是否正確;例如,服務(wù)是否存儲(chǔ)和返回有效的數(shù)據(jù)值并正確執(zhí)行數(shù)據(jù)操作。

AndroidX Test 提供了一個(gè) API,用于在隔離的環(huán)境中測(cè)試 Service 對(duì)象。ServiceTestRule 類是一個(gè) JUnit 4 規(guī)則,可在單元測(cè)試方法運(yùn)行之前啟動(dòng)服務(wù),并在測(cè)試完成后關(guān)閉服務(wù)。通過(guò)使用此測(cè)試規(guī)則,您可確保始終在測(cè)試方法運(yùn)行之前建立與服務(wù)的連接。如需詳細(xì)了解 JUnit 4 規(guī)則,請(qǐng)參閱 JUnit 文檔。

注意:ServiceTestRule 類不支持測(cè)試 IntentService 對(duì)象。如果您需要測(cè)試 IntentService 對(duì)象,應(yīng)將邏輯封裝在一個(gè)單獨(dú)的類中,并創(chuàng)建相應(yīng)的單元測(cè)試。

創(chuàng)建服務(wù)的集成測(cè)試

您的集成測(cè)試應(yīng)編寫(xiě)為 JUnit 4 測(cè)試類。如需詳細(xì)了解如何創(chuàng)建 JUnit 4 測(cè)試類以及如何使用 JUnit 4 斷言方法,請(qǐng)參閱創(chuàng)建插樁單元測(cè)試類。

如需創(chuàng)建服務(wù)的集成測(cè)試,請(qǐng)?jiān)跍y(cè)試類定義的開(kāi)頭添加 @RunWith(AndroidJUnit4::class) 注釋。您還需要將 AndroidX Test 提供的 AndroidJUnitRunner 類指定為默認(rèn)測(cè)試運(yùn)行程序。運(yùn)行插樁單元測(cè)試中對(duì)此步驟進(jìn)行了更詳細(xì)的說(shuō)明。

接下來(lái),使用 @Rule 注釋在測(cè)試中創(chuàng)建一個(gè) ServiceTestRule 實(shí)例。

 

@get:Rule val serviceRule = ServiceTestRule()

以下示例展示了如何實(shí)現(xiàn)服務(wù)的集成測(cè)試。測(cè)試方法 testWithBoundService 將驗(yàn)證應(yīng)用是否成功綁定到本地服務(wù),以及服務(wù)接口是否正常運(yùn)行。

 

@Test @Throws(TimeoutException::class) fun testWithBoundService() { // Create the service Intent. val serviceIntent = Intent( ApplicationProvider.getApplicationContext<Context>(), LocalService::class.java ).apply { // Data can be passed to the service via the Intent. putExtra(SEED_KEY, 42L) } // Bind the service and grab a reference to the binder. val binder: IBinder = serviceRule.bindService(serviceIntent) // Get the reference to the service, or you can call // public methods on the binder directly. val service: LocalService = (binder as LocalService.LocalBinder).getService() // Verify that the service is working correctly. assertThat(service.getRandomInt(), `is`(any(Int::class.java))) }

測(cè)試內(nèi)容提供器

為內(nèi)容提供程序創(chuàng)建集成測(cè)試

在 Android 中,應(yīng)用將內(nèi)容提供程序視為提供數(shù)據(jù)表而其內(nèi)部構(gòu)件不可見(jiàn)的 Google Data API。內(nèi)容提供程序可能具有許多公開(kāi)常量,但通常公開(kāi)方法即使有也很少,而且沒(méi)有公開(kāi)變量。因此,您應(yīng)僅根據(jù)提供程序的公開(kāi)成員編寫(xiě)測(cè)試。這樣設(shè)計(jì)的內(nèi)容提供程序在其自身與其用戶之間提供了約定。

內(nèi)容提供程序可讓您訪問(wèn)實(shí)際用戶數(shù)據(jù),因此請(qǐng)務(wù)必確保在隔離的測(cè)試環(huán)境中測(cè)試內(nèi)容提供程序。此方法只允許您針對(duì)在測(cè)試用例中明確設(shè)置的數(shù)據(jù)依賴項(xiàng)運(yùn)行。這也意味著,您的測(cè)試不會(huì)修改實(shí)際用戶數(shù)據(jù)。例如,您應(yīng)避免編寫(xiě)由于先前測(cè)試遺留了數(shù)據(jù)而失敗的測(cè)試。同樣,您的測(cè)試應(yīng)避免在提供程序中添加或刪除實(shí)際聯(lián)系信息。

如需在隔離環(huán)境中測(cè)試您的內(nèi)容提供程序,請(qǐng)使用 ProviderTestCase2 類。此類允許您使用 Android 模擬對(duì)象類(如 IsolatedContextMockContentResolver)訪問(wèn)文件和數(shù)據(jù)庫(kù)信息,而不會(huì)影響實(shí)際用戶數(shù)據(jù)。

您的集成測(cè)試應(yīng)編寫(xiě)為 JUnit 4 測(cè)試類。要詳細(xì)了解如何創(chuàng)建 JUnit 4 測(cè)試類以及如何使用 JUnit 4 斷言,請(qǐng)參閱創(chuàng)建本地單元測(cè)試類。

如需為您的內(nèi)容提供程序創(chuàng)建集成測(cè)試,必須執(zhí)行以下步驟:

  • 將測(cè)試類創(chuàng)建為 ProviderTestCase2 的子類。

  • 在測(cè)試類定義的開(kāi)頭添加 @RunWith(AndroidJUnit4::class) 注釋。

  • 將 AndroidX Test 提供的 AndroidJUnitRunner 類指定為默認(rèn)測(cè)試運(yùn)行程序。

  • 通過(guò) ApplicationProvider 類設(shè)置 Context 對(duì)象。請(qǐng)參閱以下代碼段中的示例。

 

@Throws(Exception::class) override fun setUp() { super.setUp() context = ApplicationProvider.getApplicationContext<Context>() }

ProviderTestCase2 的工作原理

您可以使用 ProviderTestCase2 的子類測(cè)試提供程序。該基類擴(kuò)展了 AndroidTestCase,因此它提供了 JUnit 測(cè)試框架以及用于測(cè)試應(yīng)用權(quán)限的 Android 專用方法。該類最重要的功能是其初始化,在初始化過(guò)程中可創(chuàng)建隔離的測(cè)試環(huán)境。

初始化是在 ProviderTestCase2 的構(gòu)造函數(shù)中完成的,而子類會(huì)在其自己的構(gòu)造函數(shù)中調(diào)用該過(guò)程。ProviderTestCase2 構(gòu)造函數(shù)會(huì)創(chuàng)建一個(gè) IsolatedContext 對(duì)象,該對(duì)象允許執(zhí)行文件和數(shù)據(jù)庫(kù)操作,但會(huì)對(duì)與 Android 系統(tǒng)的其他交互進(jìn)行打樁。文件和數(shù)據(jù)庫(kù)操作本身發(fā)生在設(shè)備或模擬器本地的一個(gè)帶有特殊前綴的目錄中。

然后,該構(gòu)造函數(shù)會(huì)創(chuàng)建一個(gè) MockContentResolver 用作測(cè)試的解析器。

最后,該構(gòu)造函數(shù)會(huì)創(chuàng)建一個(gè)被測(cè)提供程序的實(shí)例。這是一個(gè)普通的 ContentProvider 對(duì)象,但它會(huì)從 IsolatedContext 獲取所有環(huán)境信息,因此只能在隔離的測(cè)試環(huán)境中工作。在測(cè)試用例類中完成的所有測(cè)試都針對(duì)該隔離對(duì)象運(yùn)行。

為內(nèi)容提供程序運(yùn)行集成測(cè)試的方式與插樁單元測(cè)試相同。

要測(cè)試的內(nèi)容

以下是關(guān)于測(cè)試內(nèi)容提供程序的一些具體準(zhǔn)則。

  • 使用解析器方法進(jìn)行測(cè)試:即使您可以在 ProviderTestCase2 中實(shí)例化提供程序?qū)ο?,也?yīng)始終通過(guò)適當(dāng)?shù)?URI 使用解析器對(duì)象進(jìn)行測(cè)試。這樣做可確保您在測(cè)試提供程序時(shí)執(zhí)行的交互與常規(guī)應(yīng)用將會(huì)使用的交互相同。

  • 以約定的形式測(cè)試公開(kāi)提供程序:如果您打算將您的提供程序公開(kāi)并使其可供其他應(yīng)用使用,應(yīng)以約定的形式對(duì)其進(jìn)行測(cè)試。有關(guān)如何執(zhí)行此操作的一些示例如下所示:

    • 使用提供程序公開(kāi)的常量進(jìn)行測(cè)試。例如,查找在提供程序的其中一個(gè)數(shù)據(jù)表中引用列名稱的常量。這些常量應(yīng)始終為提供程序公開(kāi)定義的常量。

    • 測(cè)試提供程序提供的所有 URI。提供程序可能會(huì)提供多個(gè) URI,每個(gè) URI 引用數(shù)據(jù)的不同方面。

    • 測(cè)試無(wú)效的 URI:?jiǎn)卧獪y(cè)試應(yīng)故意使用無(wú)效的 URI 調(diào)用提供程序,并查找錯(cuò)誤。良好的提供程序設(shè)計(jì)是針對(duì)無(wú)效的 URI 拋出 IllegalArgumentException。

  • 測(cè)試標(biāo)準(zhǔn)提供程序交互:大多數(shù)提供程序都會(huì)提供六種訪問(wèn)方法:query()、insert()、delete()、update()getType()onCreate()。您的測(cè)試應(yīng)驗(yàn)證所有這些方法是否有效。內(nèi)容提供程序主題中對(duì)這些方法進(jìn)行了更詳細(xì)的說(shuō)明。

  • 測(cè)試業(yè)務(wù)邏輯:如果內(nèi)容提供程序?qū)崿F(xiàn)了業(yè)務(wù)邏輯,應(yīng)對(duì)其進(jìn)行測(cè)試。業(yè)務(wù)邏輯包括處理無(wú)效值、財(cái)務(wù)或算術(shù)計(jì)算、消除或合并重復(fù)項(xiàng)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-617243.html

到了這里,關(guān)于Android Unit Test的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Android 單元測(cè)試初體驗(yàn)

    Android 單元測(cè)試初體驗(yàn)

    當(dāng)初在學(xué)校學(xué)安卓的時(shí)候,老師敢教學(xué)進(jìn)度,翻到單元測(cè)試這一章節(jié)的時(shí)候提了兩句,沒(méi)有把單元測(cè)試當(dāng)重點(diǎn)講,只是說(shuō)我們工作中幾乎不會(huì)用到,果真在之前的幾年工作當(dāng)中我真的沒(méi)有用到,工作中都沒(méi)有寫(xiě)過(guò)單元測(cè)試,后來(lái)我自己也下意識(shí)的忽略了這一塊,直到聽(tīng)說(shuō)現(xiàn)在

    2024年02月03日
    瀏覽(16)
  • Android下單元測(cè)試實(shí)踐——測(cè)試框架簡(jiǎn)介

    Android下單元測(cè)試實(shí)踐——測(cè)試框架簡(jiǎn)介

    測(cè)試代碼的寫(xiě)法可以歸納為三部分 第一部分: 準(zhǔn)備測(cè)試數(shù)據(jù)和定義mock行為 第二部分: 調(diào)用真實(shí)的函數(shù) 第三部分: 調(diào)用驗(yàn)證函數(shù)進(jìn)行結(jié)果的驗(yàn)證 在模塊的test路徑下編寫(xiě)測(cè)試案例。在類中使用@Test注解,就可以告訴Junit這個(gè)方法是測(cè)試方式。同時(shí)使用assert*方法,可以調(diào)用J

    2024年02月04日
    瀏覽(20)
  • Android 單元測(cè)試之 Mockk

    relaxed : 是否對(duì)其代碼進(jìn)行依賴,默認(rèn)為否,這個(gè)參數(shù)比較關(guān)鍵,后續(xù)會(huì)更細(xì)的講解一下 moreInterfaces : 讓這個(gè)mock出來(lái)的對(duì)象實(shí)現(xiàn)這些聲明的接口 relaxUnitFun :和 relaxed 差不多,但是只針對(duì)于 返回值是Unit 的方法, 后續(xù)會(huì)講解一下 block : 該語(yǔ)句塊表示你在創(chuàng)建完 mock 對(duì)象后

    2024年02月02日
    瀏覽(22)
  • Android 單元測(cè)試之PowerMock

    Android 單元測(cè)試之PowerMock

    class PowerMockClassTest { @Test fun isFileExists() { // Mock 一個(gè) File對(duì)象 val file = PowerMockito.mock(File::class.java) // 創(chuàng)建當(dāng)前類 val powerMockitoClass = PowerMockClass() // 當(dāng)Mock對(duì)象被調(diào)用了 exists() 方法,則返回False PowerMockito. when (file.exists()).thenReturn(false) // 進(jìn)行斷言 assertFalse(file.exists()) } } 對(duì)于這種

    2024年04月23日
    瀏覽(25)
  • Python 面試:?jiǎn)卧獪y(cè)試unit testing & 使用pytest

    calc.py test_calc.py employee.py test_employee.py 輸出為: setupClass setUp test_apply_raise tearDown .setUp test_email tearDown .setUp test_fullname tearDown .teardownClass Ran 3 tests in 0.001s OK employee.py test_employee.py 輸出為: setupClass setUp test_apply_raise tearDown .setUp test_email tearDown .setUp test_fullname tearDown .setUp tearDown

    2024年02月10日
    瀏覽(27)
  • Android Studio系列-Activity單元測(cè)試,字節(jié)Android高級(jí)崗

    Android Studio系列-Activity單元測(cè)試,字節(jié)Android高級(jí)崗

    新建Activity單元測(cè)試類 =============== package com.devilwwj.unittestdemo; import android.content.Intent; import android.test.ActivityUnitTestCase; import android.test.suitebuilder.annotation.MediumTest; import android.widget.Button; /** Created by wwj_748 on 2016/2/22.17.12 */ public class LoginActivityTest extends ActivityUnitTestCase { private Inten

    2024年04月25日
    瀏覽(27)
  • Android 單元測(cè)試框架 JUnit 4

    JUnit 4測(cè)試框架,它是Java中廣泛使用的單元測(cè)試框架之一,使開(kāi)發(fā)者能夠編寫(xiě)可重復(fù)、可維護(hù)和可驗(yàn)證的測(cè)試。 單元測(cè)試是針對(duì)代碼中的個(gè)別單元或組件進(jìn)行測(cè)試,可以包括以下方面: 功能測(cè)試:測(cè)試代碼單元是否按照預(yù)期執(zhí)行功能。 邊界測(cè)試:測(cè)試代碼單元響應(yīng)不同的邊

    2024年02月15日
    瀏覽(47)
  • Android單元測(cè)試系列(3)-Mock之Mockito

    Android單元測(cè)試系列(3)-Mock之Mockito

    目錄 一、官網(wǎng) 二、Demo示例 1. 目錄結(jié)構(gòu) 2. 被測(cè)試的類 3. 測(cè)試類 三、Mockito方法說(shuō)明 1. mock對(duì)象創(chuàng)建 2. Mockito框架中的常見(jiàn)方法說(shuō)明 2.1 常見(jiàn)的打樁方法 2.2 常見(jiàn)的驗(yàn)證行為 2.3 其他方法? 3. Mockito的局限性 Mockito: https://github.com/mockito/mockito Mockito (Mockito 4.4.0 API) 為什么要用mock:

    2023年04月15日
    瀏覽(23)
  • Android單元測(cè)試系列(3)-Mock之PowerMock

    Android單元測(cè)試系列(3)-Mock之PowerMock

    目錄 一、官網(wǎng) 二、Demo示例? 三、PowerMock常用的測(cè)試方法 1. Private 1.1 私有變量 1.2 私有方法 2. Final 3. Static Android單元測(cè)試系列(3)-Mock之Mockito_Chris_166的博客-CSDN博客 Android單元測(cè)試系列(1)-開(kāi)篇_Chris_166的博客-CSDN博客 這兩篇中已經(jīng)分別介紹過(guò)Mockito的使用和局限性,本篇將介紹P

    2023年04月08日
    瀏覽(21)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包