Android自動化測試-從入門到入門(3)Espresso入門
https://segmentfault.com/a/1190000004355178
根據該系列之前的兩篇文章:Hello Testing和Testing APIs,我們已經對Android自動化測試的整體背景有了一些瞭解。還記得第一篇文章裡我提到過的基本思路麼?
把自己當成使用者,只關注我能看到的東西。
這個思路的意思是在於,我要讓機器模擬我的測試過程,那麼我就需要針對那些我(作為使用者)能看到的東西,也就是UI。比如說,我並不關心某個網路請求返回值的具體資料是否正確,我關心的是我能在UI上看到我希望看到的結果。基於此,我做各個測試用例的一個通用的思路就是:
找到某個元素,做一些操作,檢查結果。
這裡包含了三個流程:
-
找元素
:找到UI上測試所針對的元素; -
做操作
:給這個元素做一些操作; -
檢查結果
:這個元素做出了我期望的行為。
再直觀一點,我向一個表單輸入一段文字,那麼整個過程就可以描述為:
-
找元素
:找到EditText; -
做操作
:向EditText輸入字串; -
檢查結果
:EditText顯示了我輸入的字串。
以上三個小步驟實際上也是我作為使用者在使用一個APP的時候所遵循的流程。而我們的測試也是基本遵循這樣一個流程的。
Espresso
為了實現我們的自動化測試流程,我們採用Espresso
進行指令碼的編寫。我們需要在build.gradle
的dependencies
中增加如下依賴:
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
請注意,在這裡我並沒有完整地將build.gradle
貼出來,只是貼出來了需要增加的部分。這也就意味著,在第一篇Hello
Testing中提到的那些配置也都是必不可少的。
另外,我們還需要一個叫做hamcrest
的庫,用來和Espresso
配合使用,因此在build.gradle
中新增:
androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
建一個Test Case
還記得之前文章中我們提到的那個AppStartActivity
Test
Case
麼?我們可以在相應的目錄下建立我們自己的Test Case
了!這裡貼一下Espresso
官方提供的一個example:
@RunWith(AndroidJUnit4.class)
@LargeTest
public class HelloWorldEspressoTest {
@Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule(MainActivity.class);
@Test
public void listGoesOverTheFold() {
onView(withText("Hello world!")).check(matches(isDisplayed()));
}
}
要執行我們的測試用例,我們可以參照第一篇文章中採用Android Studio
的方法,也可以在終端中切換到當前專案的路徑下,執行如下命令:
./gradlew cAT
其中,cAT
意為connectedAndroidTest
。
找元素
我們現在需要找頁面中對應的元素了!Espresso
提供了一個onView()
方法用來尋找UI上指定的元素,該方法定義如下:
public static ViewInteraction onView(final Matcher<View> viewMatcher) {}
這個方法接收一個Matcher<View>
型別的入參,返回一個ViewInteraction
物件,其所做的事情就是根據Matcher<View>
所指定的條件,在當前UI頁面上尋找符合條件的View
,並且把相應的View
返回出來。這樣說還是比較抽象,我們可以用一個具體的例子加以說明。
當我們在實現佈局的時候,每個控制元件都會有一些特殊的屬性來確定其唯一性,比如最常用的R.id
。Matcher<View>
支援通過控制元件的唯一ID來從當前頁面上尋找目標控制元件,對應的方法為withId()
,該方法定義如下:
public static Matcher<View> withId(final int id) {}
大家可以看到,該方法接收了一個int
型別的入參,返回了一個Matcher<View>
物件,於是,採用如下寫法:
onView(withId(id));
我們就能在當前頁面找到指定ID所對應的目標控制元件了。
再描述一遍這個流程以便更清晰:我現在要找一個R.id
為指定id
的控制元件,那麼我就從我的這個id
出發,先生成一個查詢匹配條件:withId(id)
。然後把這個條件傳給onView()
方法:onView(withId(id))
,讓onView()
方法根據這個條件找到我們想要的那個控制元件!實際上這行程式碼也是很符合我們的正常思維,可以讀作:
Find a view with Id of the specific id.
實際上,Espresso
提供了很多方法來讓我們自定義我們的查詢條件。比如我們可以通過withText()
方法來尋找顯示了指定文案的控制元件等等。具體支援的Matcher
型別可以參考Espresso
cheat sheet。
需要提醒大家一點的是,onView()
方法在根據匹配條件進行查詢時,它的目標是找到唯一的一個目標控制元件。如果我們制定的匹配條件有多個控制元件可以匹配(比如複用了layout
的佈局,或者顯示相同文字的TextView
等),該方法會丟擲一個AmbiguousViewMatcherException
異常,因此我們在構造匹配條件時,一定要確保能查詢到的目標控制元件是唯一的。如果單一的匹配條件無法精確地匹配出來唯一的控制元件,我們可能還需要額外的匹配條件,此時可以用allOf()
方法來進行復合匹配條件的構造:
onView(allOf(withId(id), withText(text)))
以上程式碼可以查詢ID
為id
同時顯示的文字內容為text
的控制元件。這裡需要注意的是,為了保證自動化測試的效率,我們應儘可能減少匹配條件的數量。如果用一個匹配條件能夠滿足我們的需求,我們也就沒有必要再用allOf()
來構造複合匹配條件了。
操作元素
找到了目標元素,接下來我們該針對該元素做一些操作了!Espresso
提供瞭如下方法來對相應的元素做操作:
public ViewInteraction perform(final ViewAction... viewActions) {}
該方法定義在ViewInteraction
類裡面。還記得onView()
方法的返回值麼?yes,正是一個ViewInteraction
物件。因此,我們可以在onView()
方法找到的元素上直接呼叫perform()
方法進行一系列操作:
onView(withId(id)).perform(click())
如上程式碼對onView()
查詢到的元素做了一次點選的操作。請注意,perform()
方法的入參是變長引數,也就意味著,我們可以依次對某個元素做多個操作:
onView(withId(id)).perform(click(), replaceText(text), closeSoftKeyboard())
以上程式碼對目標元素依次做了點選、輸入文字、關閉輸入法鍵盤的操作。這是一個典型的填寫表單的行為。
檢查結果
到目前為止,我們已經能找到元素,也能夠對元素進行一些操作了!接下來我們需要檢查一下這些操作的結果是否符合我們的預期。
Espresso
提供了一個check()
方法用來檢測結果:
public ViewInteraction check(final ViewAssertion viewAssert) {}
該方法接收了一個ViewAssertion
的入參,該入參的作用就是檢查結果是否符合我們的預期。一般來說,我們可以呼叫如下的方法來自定義一個ViewAssertion
:
public static ViewAssertion matches(final Matcher<? super View> viewMatcher) {}
這個方法接收了一個匹配規則,然後根據這個規則為我們生成了一個ViewAssertion
物件!還記得Matcher
這個型別麼!!是的,這就是onView()
方法的入參!實際上他們是同一個型別,其使用方法也是完全一致的。
比如,我想檢查一下指定id
的TextView
是否按照我的預期顯示了一段text
文字,那麼我就可以這樣寫:
onView(withId(id)).check(matches(withText(text)))
簡潔明瞭。ViewAssertion
的支援也可以參照這個Espresso
cheat sheet。
恭喜入門!
到目前為止,我們已經使用Espresso
完成了一個小的測試流程。如果你都看懂了,那麼恭喜你,你已經成功入門,可以寫一些簡單的Test
Case
了!
那麼回過頭來,我們就可以理解本文開頭貼出來的Espresso
官網提供的那個小案例了。在listGoesOverTheFold()
方法中,只執行了一行程式碼:
onView(withText("Hello world!")).check(matches(isDisplayed()));
其意義也已經足夠明晰:檢查"Hello world!"
是否成功地顯示在了螢幕上。