標籤:min 允許 第一個 data 組合 繼承 nss author miss
Android測試(七):Espresso 自動化測試
發布時間 2017年12月20日 蟲師
原文:https://developer.android.com/training/testing/ui-testing/espresso-testing.html
在單個應用程式中測試使用者互動有助於確保使用者在與應用程式進行互動時不會遇到意外的結果,或遇到糟糕的體驗。 如果需要驗證應用的UI功能是否正常,則應該養成建立使用者介面(UI)測試的習慣。
Espresso 測試架構,由Android測試支援庫提供,用於編寫UI測試的API來類比單個應用程式內的使用者互動。Espresso測試可以在運行Android 2.3.3(API等級10)及更高版本的裝置上運行。 使用Espresso的一個關鍵好處是,它提供了測試操作與正在測試的應用程式的使用者介面的自動同步。 Espresso檢測主線程是否處於空閑狀態,以便能夠在適當的時候運行測試命令,從而提高測試的可靠性。此功能還可以減輕在測試代碼中添加任何計時變通方法如Thread.sleep()
的麻煩。
Espresso測試架構基於instrumentation的API,並通過AndroidJUnitRunner運行測試。
設定Espresso
在使用Espresso構建UI測試之前,請確保配置測試原始碼位置和項目依賴關係,如“ Getting Started with Testing”中所述。
在Android應用程式模組的build.gradle檔案中,必須設定對Espresso庫的依賴關係引用:
dependencies { // Other dependencies ... androidTestCompile ‘com.android.support.test.espresso:espresso-core:2.2.2‘}
關閉測試裝置上的動畫 - 在測試裝置中開啟系統動畫可能會導致意外的結果,或者可能導致測試失敗。 通過開啟“開發人員”選項關閉“設定”中的動畫,並關閉以下所有選項:
如果你希望將項目設定為使用核心API提供的Espresso功能以外的功能,請參閱此資源
建立一個Espresso 測試
要建立Espresso測試,請建立遵循此編程模型的Java類:
1.找到想要在活動中測試的UI組件(例如,應用程式中的登入按鈕),調用onView()方法,或者調用AdapterView控制項的onData()方法。
2.通過調用ViewInteraction.perform()或DataInteraction.perform()方法並傳入使用者操作(例如,單擊登入按鈕),類比特定的使用者互動以在該UI組件上執行。 要在同一UI組件上對多個操作進行排序,請使用方法參數中的逗號分隔列錶鏈接它們。
3.根據需要重複上述步驟,類比目標應用中多個活動的使用者操作。
4.在執行這些使用者互動之後,使用ViewAssertions
方法來檢查UI是否反映了期望的狀態或行為。
以下各節將詳細介紹這些步驟。
下面的程式碼片段顯示了你的測試類別可能如何調用這個基本的工作流程:
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
以下部分介紹如何使用JUnit 4樣式建立新的Espresso測試,並使用ActivityTestRule來減少需要編寫的樣板代碼的數量。 通過使用ActivityTestRule,測試架構在每個使用@Test
注釋的測試方法之前以及在使用@Before
注釋的方法之前啟動被測活動。測試完成後,架構處理關閉活動,所有使用@After
注釋的方法都會運行。
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 android.support.test.rule.ActivityTestRule;import android.support.test.runner.AndroidJUnit4;...@RunWith(AndroidJUnit4.class)@LargeTestpublic class ChangeTextBehaviorTest { private String mStringToBetyped; @Rule public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>( MainActivity.class); @Before public void initValidString() { // Specify a valid string. mStringToBetyped = "Espresso"; } @Test public void changeText_sameActivity() { // Type text and then press the button. onView(withId(R.id.editTextUserInput)) .perform(typeText(mStringToBetyped), closeSoftKeyboard()); onView(withId(R.id.changeTextBt)).perform(click()); // Check that the text was changed. onView(withId(R.id.textToBeChanged)) .check(matches(withText(mStringToBetyped))); }}
訪問UI組建
在Espresso可以與被測試的應用程式進行互動之前,必須先指定UI組件或視圖。Espresso支援使用Hamcrest 匹配器在應用程式中指定視圖和適配器。
要查詢檢視表,請調用onView()
方法並傳遞一個視圖匹配器,該視圖匹配器指定要定位的視圖。 這在指定視圖匹配器中有更詳細的描述。 onView()
方法返回ViewInteraction
對象,允許測試與視圖進行互動。 但是,如果要在RecyclerView
布局中查詢檢視表,則調用onView()
方法可能不起作用。 在這種情況下,請按照在AdapterView中查詢檢視表中的說明進行操作。
注意:onView()方法不檢查你指定的視圖是否有效。相反,Espresso只搜尋當前的視圖階層,使用matcher提供的視圖。如果沒有找到匹配,該方法將拋出一個NoMatchingViewException。
下面的程式碼片段展示了如何編寫一個測試來訪問EditText欄位,輸入一個文本字串,關閉虛擬鍵盤,然後執行按鈕單擊。
public void 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. ...}
指定一個視圖匹配器
您可以使用以下方法指定視圖匹配器:
- 在ViewMatchers類中調用方法。 例如,要尋找顯示的文本字串來查詢檢視表,可以調用如下所示的方法:
onView(withText("Sign-in"));
也可以調用withId()並提供視圖的資源ID(R.id),如下例所示:
onView(withId(R.id.button_signin));
Android資源ID不保證是唯一的。 如果測試嘗試匹配多個視圖使用的資源ID,則Espresso會引發AmbiguousViewMatcherException。
- 使用Hamcrest Matchers類。可以使用
AllOf()
方法來組合多個匹配器,例如containsString()
和instanceOf()
。 這種方法允許更窄地過濾匹配結果,如以下樣本所示:
onView(allOf(withId(R.id.button_signin), withText("Sign-in")));
但是,不能使用關鍵字來篩選不匹配匹配器的視圖,如以下樣本所示:
onView(allOf(withId(R.id.button_signin), not(withText("Sign-out"))));
要在測試中使用這些方法,請匯入org.hamcrest.Matchers
包。 要瞭解有關Hamcrest匹配的更多資訊,請參閱Hamcrest網站
要改善Espresso測試的效能,請指定尋找目標視圖所需的最低匹配資訊。例如,如果某個視圖可以通過其描述性文本唯一標識,則不需要指定它也可以從TextView執行個體分配。
在AdapterView中查詢檢視表
在AdapterView小組件中,視圖在運行時動態填充子視圖。 如果要測試的目標視圖位於AdapterView中(如ListView,GridView或Spinner),則onView()
方法可能無法正常工作,因為只有視圖的子集可能會載入到當前視圖階層中。
相反,調用onData()
方法來擷取DataInteraction對象來訪問目標視圖元素。 Espresso將目標視圖元素載入到當前視圖階層中。 Espresso還負責滾動目標元素,並將元素放在焦點上。
注意:onData()方法不會檢查你指定的項目是否與視圖對應。Espresso只搜尋當前的視圖階層。如果找不到匹配,則該方法將引發NoMatchingViewException。
以下程式碼片段顯示了如何使用onData()
方法和Hamcrest匹配一起搜尋包含給定字串的列表中的特定行。 在此樣本中,LongListActivity類包含通過SimpleAdapter公開的字串列表。
onData(allOf(is(instanceOf(Map.class)), hasEntry(equalTo(LongListActivity.ROW_TEXT), is("test input")));
執行操作
調用 ViewInteraction.perform()
或 DataInteraction.perform()
方法來類比UI組件上的使用者互動。 您必須傳入一個或多個ViewAction對象作為參數。 Espresso根據給定的順序依次觸發每個動作,並在主線程中執行它們。
ViewActions類提供了用於指定常用操作的協助程式方法列表。 可以使用這些方法作為方便的捷徑,而不是建立和配置單獨的ViewAction對象。 你可以指定如下操作:
ViewActions.click():點擊視圖。
ViewActions.typeText():點擊一個視圖並輸入一個指定的字串。
ViewActions.scrollTo():滾動到視圖。 目標視圖必須從ScrollView繼承,其android:visibility屬性的值必須是可見的。 對於擴充AdapterView的視圖(例如,ListView),onData()方法負責為您滾動。
ViewActions.pressKey():使用指定的鍵碼進行按鍵動作。
ViewActions.clearText():清除目標視圖中的文本。
如果目標視圖位於ScrollView的內部,則先執行ViewActions.scrollTo()
操作,然後再執行其他動作。 如果已經顯示視圖,則ViewActions.scrollTo()
操作將不起作用。
用Espresso Intents隔離測試你的活動
Espresso Intents可以驗證應用程式發送的意圖的驗證和存根。 通過Espresso Intents,可以通過攔截傳出的意圖,對結果進行存根並將其發送回被測組件來隔離測試應用程式,活動或服務。
dependencies { // Other dependencies ... androidTestCompile ‘com.android.support.test.espresso:espresso-intents:2.2.2‘}
為了測試一個intent,你需要建立一個IntentsTestRule類的執行個體,它與ActivityTestRule類非常相似。 IntentsTestRule類在每次測試之前初始化Espresso Intents,終止主活動,並在每次測試後釋放Espresso Intents。
以下程式碼片段中顯示的測試類別為明確的意圖提供了一個簡單的測試。 它測試建立你的第一個應用程式教程中建立的活動和意圖。
@Large@RunWith(AndroidJUnit4.class)public class SimpleIntentTest { private static final String MESSAGE = "This is a test"; private static final String PACKAGE_NAME = "com.example.myfirstapp"; /* Instantiate an IntentsTestRule object. */ @Rule public IntentsTestRule?MainActivity> mIntentsRule = new IntentsTestRule?>(MainActivity.class); @Test public void 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 Intents的更多資訊,請參閱Android測試支援庫網站上的Espresso Intent文檔。 您還可以下載IntentsBasicSample和IntentsAdvancedSample程式碼範例。
用Espresso Web測試WebViews
Espresso Web允許測試活動中包含的WebView組件。 它使用WebDriver API來檢查和控制WebView的行為。
要開始使用Espresso Web進行測試,需要將以下行添加到應用程式的build.gradle檔案中:
dependencies { // Other dependencies ... androidTestCompile ‘com.android.support.test.espresso:espresso-web:2.2.2‘}
使用Espresso Web建立測試時,需要在執行個體化ActivityTestRule對象以測試活動時在WebView上啟用JavaScript。 在測試中,可以選擇顯示在WebView中的HTML元素,並類比使用者互動,例如在文字框中輸入文本,然後單擊按鈕。在完成操作後,你可以驗證網頁上的結果是否符合預期結果。
在以下程式碼片段中,這個類測試一個WebView組件,該組件的id值“WebView”在被測試的活動中。 verifyValidInputYieldsSuccesfulSubmission()
測試選擇網頁上的<input>
元素,輸入一些文本,並檢查出現在另一個元素中的文本。
@LargeTest@RunWith(AndroidJUnit4.class)public class WebViewActivityTest { private static final String MACCHIATO = "Macchiato"; private static final String DOPPIO = "Doppio"; @Rule public ActivityTestRule mActivityRule = new ActivityTestRule(WebViewActivity.class, false /* Initial touch mode */, false /* launch activity */) { @Override protected void afterActivityLaunched() { // Enable JavaScript. onWebView().forceJavascriptEnabled(); } } @Test public void typeTextInInput_clickButton_SubmitsForm() { // Lazily launch the Activity with a custom start Intent per test mActivityRule.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))); }}
有關Espresso Web的更多資訊,請參閱Android測試支援庫網站上的Espresso Web文檔。您也可以將此程式碼片段作為Espresso Web程式碼範例的一部分下載。
驗證結果
調用ViewInteraction.check()
或DataInteraction.check()
方法來聲明UI中的視圖匹配某個預期的狀態。 必須傳遞給ViewAssertion對象作為參數。如果宣告失敗,Espresso將拋出一個AssertionFailedError。
ViewAssertions類提供了用於指定公用斷言的協助器方法列表。 你可以使用的斷言包括:
doesNotExist:斷言當前視圖階層中沒有與指定條件匹配的視圖。
matches:斷言指定的視圖存在於當前的視圖階層中,並且其狀態匹配給定的Hamcrest匹配器。
selectedDescendentsMatch:聲明指定的父視圖的子視圖存在,並且它們的狀態匹配給定的Hamcrest匹配器。
以下程式碼片段顯示如何檢查使用者介面中顯示的文本與先前在EditText欄位中輸入的文本具有相同的值。
public void 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)));}
在裝置或模擬器上運行Espresso測試
你可以從Android Studio或從命令列運行Espresso測試。 確保將AndroidJUnitRunner指定為項目中的預設偵查工具。
要運行Espresso測試,請按照前面章節介紹的步驟運行已測試的測試。
Android測試(七):Espresso 自動化測試