Ang Pag-test sa Android User Interfaces Gamit Ang Espresso
() translation by (you can also view the original English article)
Sa post na ito,
matututunan ninyo ang tungkol sa lung papaano sumulat ng mga UI tests gamit ang
Espresso testing framework at i-automate ang daloy ng iyong pagtetest, sa halip
na gumamit ng mabusisi at madalas magkamali na manual na proseso.
Ang Espresso ay isang testing framework para sa pagsusulat ng UI tests sa Android. Ayon sa mga opisyal na docs, maaari mong:
Gamitin ang Espresso upang magsulat ng maiksi, maganda at maaasahang Android UI tests.
1. Bakit Gagamit ng Espresso?
Isa sa mga problema sa manual testing ay maaari itong maging matagal at mabusisi gawin. Halimbawa, para makapag-test ng login screen (sa manual) sa isang Android app, kailangan mong gawin ang mga sumusunod:
- Ilunsad ang app.
- Tumungo sa login screen.
- Kumpirmahin kung
ang mga
usernameEditText
atpasswordEditText
ay visible. - I-type ang username at passwords sa kanilang mga nakalaang fields.
- Kumpirmahin kung ang pindutan para sa login ay kita rin, pagkatapos ay pindutin ang login button na iyon.
- I-check kung ang mga tamang views ay ipinapakita kapag tagumpay ang login o kung ito’y bigo.
Sa halip na
magaksaya ng oras sa manual na pagtetesting ng ating app, mas maganda kung
ilalaan natin ang oras na ito sa pagsulat ng code na maaaring makapagpaangatt
ng app natin mula sa iba! At, kahit na ang manual testing ay mabusisi at halos
mabagal, ito ay talagang error-prone at maaari kang maka-miss ng ilang corner
cases.
Ilan sa mga kalamangan ng automated testing ay kinasasamahan ng mga sumusunod:
- Ginagawa ng automated texts ang eksaktong parehong test cases tuwing ang mga ito ay i-eexecute.
- Mabilis makikita ng mga developer ang problema bago pa man ito maipadala sa QA team.
- Makakatipid ito ng lubusan sa oras, di gaya ng paggawa ng manual testing. Sa pagtitipid sa oras, ang mga software engineer at ang QA team ay maaaring mas maglaan ng panahon sa mga mapaghamon at kapaki-pakinabang na mga gawain.
- Mas mataas na test coverage ang makukuha, na magbibigay daan tungo sa mas magandang kalidad na application.
Sa pagtuturong
ito, matututunan natin ang tungkol sa Espresso sa pamamagitan ng pag-integrate
ditto sa isang proyekto sa Android Studio. Magsusulat tayo ng mga UI tests para
sa isang login screen at isang RecyclerView
, at matututunan natin ang tungkol
sa pagtest ng mga intents.
Ang kalidad ay hindi nakukuha sa pagkabisa, kundi sa pagsasanay. — Pablo Picasso
2. Mga Pangunahing Kailangan
Para masundan ang
pagtuturong ito, kakailanganin ninyo ang mga sumusunod:
- payak na kaalaman tungkol sa ubod ng Android APIs at Kotlin
- Android Studio 3.1.3 o mas mataas pa
- Kotlin plugin 1.2.51 o mas mataas pa
Isang sample na protekyo (sa Kotlin) para sa pagtuturong ito ang matatagpuan sa ating GitHub repo para mas madali kang makasunod.
3. Gumawa ng isang Proyekto sa Android Studio
Buksan na ang
Android Studio 3 at gumawa ng bagong proyekto gamit ang isang empty activity na
tatawaging MainActivity
. Siguruhing i-check ang Include Kotlin support.



4. I-setup ang
Espresso at AndroidJUnitRunner
Matapos ang paggawa ng bagong proyekto, siguruhin na idagdag ang mga sumusunod na mga dependencies mula sa Android Testing Support Library sa iyong build.gradle (maski na isinama na ito ng Android Studio para sa atin). Sa pagtuturong ito, gagamitin natin ang pinakabagong bersyon ng Espresso library 3.0.2 (sa panahon ng pagkasulat nito)
1 |
android { |
2 |
//...
|
3 |
defaultConfig { |
4 |
//...
|
5 |
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" |
6 |
}
|
7 |
//...
|
8 |
}
|
9 |
|
10 |
dependencies { |
11 |
//...
|
12 |
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' |
13 |
androidTestImplementation 'com.android.support.test:runner:1.0.2' |
14 |
androidTestImplementation 'com.android.support.test:rules:1.0.2' |
15 |
|
16 |
}
|
Isinama rin natin
ang instrumentation runner na AndroidJUnitRunner
:
Isang
Instrumentation
na nagpapagana ng JUnit3 at JUnit4 na mga tests para sa isang
Android package (application).
Tandaan na ang
Instrumentation
ay isa lamang base class para sa pagpapatupad ng application
instrumentation code.
Isara ang Animation
Ang synchronization ng Espresso, na hindi alam kung papaano maghintay na matapos ang isang animation, ay maaaring magdulot ng ilang mga tests na mabigo-kung hahayaan ang animation sa test device. Para maisara ang animation sa iyong test device, tumungo sa Settings > Developer Options at i-turn off ang mga sumusunod na mga pagpipilian sa ilalim ng “Drawing” section:
- Window animation scale
- Transition animation scale
- Animator duration scale
5. Isulat ang Iyong Unang Test sa Espresso
Una, sisimulan
nating i-test ang Login screen. Ganito gumagana ang daloy ng login: ilulunsad
ng user ang app, at ang unang screen na ipapakita ay naglalaman ng isang Login
button. Kapag ang Login
button ay napindot, bubuksan nito ang LoginActivity
screen. Ang screen na ito
ay naglalaman lang ng dalawang EditTexts
(mga fields para sa username at
password) at Submit button.
Ganito dapat ang
magiging itsura ng ating MainActivity
:



Ganito dapat ang magiging itsura ng ating LoginActivity
:



Ngayon naman ay
sumulat tayo ng test para sa ating MainActivity
class. Tumungo sa MainActivity
class, itutok ang cursor sa MainActivity
, at pindutin ang
Shift-Control-T. Piliin ang Create New Test sa popup menu.



Pindutin ang OK, at isa pang dialog ang lalabas. Piliin ang androidTest directory at pindutin ang OK ng isa pang beses. Tandaan na dahil nagsusulat tayo ng instrumentation test (mga test na tiyak para sa Android SDK), ang mga test cases ay nakalagay sa androidTest/java na folder.
Ngayon,
matagumpay nang nakagawa ng isang test class ang Android Studio para sa atin.
Sa itaas ng class name, isama itong annotation: @RunWith(AndroidJUnit4::class)
.
1 |
import android.support.test.runner.AndroidJUnit4 |
2 |
import org.junit.runner.RunWith |
3 |
|
4 |
@RunWith(AndroidJUnit4::class) |
5 |
class MainActivityTest { |
6 |
|
7 |
|
8 |
}
|
Ang annotation na ito ay sumisimbolo na ang lahat ng tests sa class na ito ay tiyak para sa Android.
Pagtest ng mga
Activities
Dahil gusto nating mag-test ng isang Activity, kailangan natin gumawa ng kaunting setup. Kailangan nating ipaalam sa Espresso kung anong Activity ang bubuksan o ilulunsad bago i-execute at sirain pagkatapos i-execute ang kahit na anong test method.
1 |
import android.support.test.rule.ActivityTestRule |
2 |
import android.support.test.runner.AndroidJUnit4 |
3 |
import org.junit.Rule |
4 |
import org.junit.runner.RunWith |
5 |
|
6 |
@RunWith(AndroidJUnit4::class) |
7 |
class MainActivityTest { |
8 |
|
9 |
@Rule @JvmField |
10 |
var activityRule = ActivityTestRule<MainActivity>( |
11 |
MainActivity::class.java |
12 |
)
|
13 |
|
14 |
}
|
Tandaan na ang
@Rule
na annotation ay nangangahulugan na ito ay isang JUnit4 na test rule. Ang
mga JUnit4 na test rules ay pinapagana bago at pagkatapos ang bawat test method
(na ina-annotate gamit ang @Test
). Sa ating sariling
scenario, gusto natin na ilunsad ang MainActivity
bago ang bawat test method at
sirain din ito pagkatapos.
Sinama din natin
ang @JvmField
Kotlin na annotation. Sinasabi lang nito sa compler na wag
mag-generate ng getters at setters para sa property at sa halip ay ilantad ito
bilang isang simpleng Java field.
Narito ang tatlong pangunahing hakbang sa pagsulat ng isang Espresso test:
- Hanapin ang
widget (halimbawa,
TextView
oButton
) na gusto mong i-test. - Gawin ang isa o higit pang mga actions sa widget na ito.
- I-verify o i-check para makita kung and widget ay nasa isang tiyak na estado na.
Ang mga sumusunod
ang mga tipo ng annotations na maaaring i-apply sa mga methods na ginamit sa
loob ng test class.
-
@BeforeClass
: ipinapakita nito na ang static method kung saan inilagay ang annotation na ito ay kailangang mai-execute ng isang beses at bago ang lahat ng mga tests sa loob ng class. Maaari itong gamitin, halimbawa, para magsetup ng connection sa isang database. -
@Before
: ipinapakita nito na ang method kung saan nakalakip ang annotation na ito ay kailangang mai-execute bago ang bawat test method sa loob ng class. -
@Test
: ipinapakita nito na ang method kung saan nakalakip ang annotation na to ay dapat gagana bilang isang test case. -
@After
: ipinapakita nito na ang method kung saan nakalakip ang annotation na to ay dapat gagana pagkatapos ng bawat test method. -
@AfterClass
: ipinapakita nito na ang method kung saan nakalakip ang annotation na to ay dapat gagana pagkatapos ang lahat ng test methods sa loob ng class ay napagana na. Dito, isinasara lang nating ang mga resources na nabuksan sa@BeforeClass
.
Humanap ng isang
View
Gamit Ang onView()
Sa ating
MainActivity
layout file, mayroon lang tayong isang widget-ang Login
button.
Sumubok tayo ng isang scenario kung saan ang isang user ay mahahanap at
maki-click ang pindutan na ito.
1 |
import android.support.test.espresso.Espresso.onView |
2 |
import android.support.test.espresso.matcher.ViewMatchers.withId |
3 |
|
4 |
// ...
|
5 |
@RunWith(AndroidJUnit4::class) |
6 |
class MainActivityTest { |
7 |
|
8 |
// ...
|
9 |
|
10 |
@Test
|
11 |
@Throws(Exception::class) |
12 |
fun clickLoginButton_opensLoginUi() { |
13 |
onView(withId(R.id.btn_login)) |
14 |
}
|
15 |
}
|
Para maghanap ng
widgets sa Espresso, gagamitin natin ang onView(
) static method (kaysa sa
findViewByID()
). Ang parameter type na ipapasa natin sa onView()
ay isang
Matcher
. Tandaan na ang Matcher
na API ay hindi galling sa Android SDK ngunit sa halip ay sa
Hamcrest Project. Ang matcher library ng Hamcrest ay nasa loob ng Espresso
library na kinuha natin sa pamamagitan ng Gradle.
Ang onView (na
may Id na(R.id.btn_login))
ay magbabalik ng ViewInteraction
na para sa isang
View
na ang ID ay R.id.btn.login
. Sa halimbawa sa itaas, gumamit tayo ng
withId()
para hanapin ang isang widget gamit ang ID. Ang iba pang view matchers
na maaari nating gamitin ay:
-
withText()
: nagbabalik ng isang matcher na nagtutugma ngTextView
ayon sa text property value nito. -
withHint()
: nagbabalik ng isang matcher na nagtutugma ngTextView
ay base sa hint property value
-
withTagKey()
: nagbabalik ng isang matcher na nagtutugma ngView
ay base sa tag keys.
-
withTagValue()
: nagbabalik ng isang matcher na nagtutugma ngView
ay base sa tag property values.
Una, i-test natin para makita kung ang pindutan ay talagang naipapakita sa screen.
1 |
onView(withId(R.id.btn_login)).check(matches(isDisplayed())) |
Dito, sinisiguro
lang nating kung ang pindutan na may aid na (R.id.btn_login
) ay nakikita ng
user, kaya gagamitin natin ang thecheck()
na method para masiguro kung ang View
na nasa ilalim nito ay mayroong tiyak na estado-sa kaso natin, kung ito ay
visible.
Ang matches()
na
static method ay nagbabalik ng isang generic ViewAssertion
na nag-aassert ng
isang view ay nakapaloob sa view hierarchy at nakatugma sa binigay na view
matcher. Ang ninigay na view matcher ay maibabalik sa pamamagitan ng pagtawag
sa isDisplayed()
. Gaya ng
minumungkahi ng method name, ang isDisplayed()
ay isang matcher na nagtutugma
ng View
s na kasalukuyang naka-display sa screen sa user. Halimbawa, kung gusto
nating i-check kung ang isang pindutan ay enabled, kailangan lang nating ipasa
ang isEnabled()
sa matches()
Ang iba pang mga
view matchers na maaari nating into sa matches()
method ay ang:
-
hasFocus()
: nagbabalik ng isang matcher na nagtutugma ngView
s na kasalukuyang may focus. -
isChecked()
: nagbabalik ng isang matcher na nagtutugma ng na tumatanggap lang kapag ang view ay isangCompoundButton
(o isang subtype ng) at nasa checked na state. Ang kabaliktaran ng method na ito ay angisNotChecked()
. -
isSelected()
: nagbabalik ng isang matcher na nagtutugma ngView
s na kasalukuyang ay pinili.
Para paganahin ang test, maaari kang mag-click sa berdeng tatsulok sa tabi ng method o ng pangalan ng class. Ang pagpindot sa berdeng tatsulok sa tabi ng class name ay magpapagana sa lahat ng test methods sa class na iyon, habang ang sa tabi ng method ay papaganahin ang test para lang sa method na iyon.



Yehey! Pumasa ang ating test!



Magsagawa ng mga Actions sa Isang View
Sa isang
ViewInteraction
na nai-return sa pamamagitan ng pagtawag sa onView()
, maaari tayong
mag-simulate ng mga pwedeng gawin ng user sa isang widget. Halimbawa, pwede
tayong mag-simulate ng isang click action sa pamamagitan ng pagtawag sa click(
)
na static method sa loob ng ViewActions
na class. Magbabalik ito ng isang
ViewAction
object para sa atin.
Sinasabi ng
documentation na ang ViewAction
ay:
Responsible sa paggawa ng isang interaction sa binigay na View element.
1 |
@Test
|
2 |
fun clickLoginButton_opensLoginUi() { |
3 |
// ...
|
4 |
|
5 |
onView(withId(R.id.btn_login)).perform(click()) |
6 |
}
|
Gagawin natin ang
click event sa pamamagitan ng pagtawag sa perform()
, bilang simula. Ang method
na ito ay ginagawa ang mga binigay na action(s) sa view na pinili ng
kasalukuyang view matcher. Tandaan na maaari
natin itong pasahan ng isang aksyon o isang listahan ng aksyon (na ipapatupad
ayon sa pagkakasunod-sunod). Narito, binigyan natin ito ng click()
. Ang iba pang mga
posibleng actions ay ang:
-
typeText()
para gayahin ang typing text papunta sa isangEditText
-
clearText()
para i-simulate ang pagbura ng text sa isangEditText
. -
doubleClick(
) para mag-simulate ng pag-double-click ng isangView
. -
longClick()
para gayahin ang pagpindot ng matagal sa isangView
. -
scrollTo()
para mai-simulate ang pagscroll sa isangScrollView
tungo sa isang tiyak naView
na nakikita. -
swipeLeft()
para i-simulate ang pag-swipe mula kanan pakaliwa sa kabila ng patayong center ng isangView
.
Marami pang ibang
simulations ang maaaring matagpuan sa loob ng ViewActions
na class.
Magvalidate Gamit Ang View Assertions
Kumpletuhin na
natin ang ating test, upang i-validate na ang LoginActivity
screen ay
pinapakita kapag ang Login button ay pinipindot. Maski na nakita na natin kung
papaano gamitin ang check()
sa isang ViewInteraction
, gamitin natin ito muli,
sa pamamamagitan ng pagpasa rito ng isa pang ViewAssertion
.
1 |
@Test
|
2 |
fun clickLoginButton_opensLoginUi() { |
3 |
// ...
|
4 |
|
5 |
onView(withId(R.id.tv_login)).check(matches(isDisplayed())) |
6 |
}
|
Sa loob ng layout
file ng LoginActivity
, bukod sa EditText
s at sa Button
, mayroon din tayong
isang TextView
gamit ID R.id.tv_login
. Kaya naman gagawa lang tayo ng
chek upang masiguro na ang TextView
ay makikita para sa user.
Ngayon ay maaari muli tayong magpaandar ng test!



Dapat ay matagumpay na papasa ang inyong mga test kung sinundan ninyo ang lahat ng mga hakbang ng tama.
Narito ang nangyari habang ipinapatupad ang proseso ng ating mga tests:
- Inilunsad ang
MainActivity
gamit angactivityRule
na field. - Siniguro kung ang
pindutan ng Login (
R.id.btn_login
) ay nakikita (isDisplayed()
) sa user.
- Nagsimulate ng isang
click action (
click()
) sa pindutan na iyon. - Pinatunayan kung
ang
LoginActivity
ay naipakita sa user sa pamamagitan ng pagcheck kung ang isangTextView
na may id naR.id.tv_login
saLoginActivity
ay nakikita.
Maaari ka lagging
sumangguni sa Espresso cheat sheet para Makita ang iba-ibang view matchers,
view actions at view assertions na pwedeng gawin.
6. I-test ang
LoginActivity
Screen
Narito ang ating LoginActivity.kt:
1 |
import android.os.Bundle |
2 |
import android.support.v7.app.AppCompatActivity |
3 |
import android.widget.Button |
4 |
import android.widget.EditText |
5 |
import android.widget.TextView |
6 |
|
7 |
class LoginActivity : AppCompatActivity() { |
8 |
|
9 |
private lateinit var usernameEditText: EditText |
10 |
private lateinit var loginTitleTextView: TextView |
11 |
private lateinit var passwordEditText: EditText |
12 |
private lateinit var submitButton: Button |
13 |
|
14 |
override fun onCreate(savedInstanceState: Bundle?) { |
15 |
super.onCreate(savedInstanceState) |
16 |
setContentView(R.layout.activity_login) |
17 |
|
18 |
usernameEditText = findViewById(R.id.et_username) |
19 |
passwordEditText = findViewById(R.id.et_password) |
20 |
submitButton = findViewById(R.id.btn_submit) |
21 |
loginTitleTextView = findViewById(R.id.tv_login) |
22 |
|
23 |
submitButton.setOnClickListener { |
24 |
if (usernameEditText.text.toString() == "chike" && |
25 |
passwordEditText.text.toString() == "password") { |
26 |
loginTitleTextView.text = "Success" |
27 |
} else { |
28 |
loginTitleTextView.text = "Failure" |
29 |
}
|
30 |
}
|
31 |
}
|
32 |
}
|
Sa code sa itaas, kung ang ini-enter na username ay “chike” at ang password ay “password”, ang login ay magiging matagumpay. Para sa iba pang input, ito ay mabibigo. Sumulat tayo ng isang Espresso test para dito!
Tumungo sa
LoginActivity.kt, igalaw ang cursor sa pangalan ng LoginActivity
, at pindutin
ang Shift-Control-T. Piliin ang Create New Test... sa popup menu. Sundan ang parehong proseso
na ginawa natin sa MainActivity.kt, at pindutin ang OK na pindutan.
1 |
import android.support.test.espresso.Espresso |
2 |
import android.support.test.espresso.Espresso.onView |
3 |
import android.support.test.espresso.action.ViewActions |
4 |
import android.support.test.espresso.assertion.ViewAssertions.matches |
5 |
import android.support.test.espresso.matcher.ViewMatchers.withId |
6 |
import android.support.test.espresso.matcher.ViewMatchers.withText |
7 |
import android.support.test.rule.ActivityTestRule |
8 |
import android.support.test.runner.AndroidJUnit4 |
9 |
import org.junit.Rule |
10 |
import org.junit.Test |
11 |
import org.junit.runner.RunWith |
12 |
|
13 |
@RunWith(AndroidJUnit4::class) |
14 |
class LoginActivityTest { |
15 |
|
16 |
@Rule
|
17 |
@JvmField
|
18 |
var activityRule = ActivityTestRule<LoginActivity>( |
19 |
LoginActivity::class.java |
20 |
)
|
21 |
|
22 |
private val username = "chike" |
23 |
private val password = "password" |
24 |
|
25 |
@Test
|
26 |
fun clickLoginButton_opensLoginUi() { |
27 |
onView(withId(R.id.et_username)).perform(ViewActions.typeText(username)) |
28 |
onView(withId(R.id.et_password)).perform(ViewActions.typeText(password)) |
29 |
|
30 |
onView(withId(R.id.btn_submit)).perform(ViewActions.scrollTo(), ViewActions.click()) |
31 |
|
32 |
Espresso.onView(withId(R.id.tv_login)) |
33 |
.check(matches(withText("Success"))) |
34 |
}
|
35 |
}
|
Ang test class na
ito ay sobrang pareho sa una. Kung papaganahin ang test, ang ating
LoginActivity
screen ay mabubuksan. Kung ang username at password ay itinala sa
R.id.et_username
ay R.id.ey_password
na mga fields. Susunod,
iki-click ng Espresso ang pindutan ng Submit (R.id.btn_submit
). Maghihintay ito
hanggang ang View
na may id na R.id.tv_login
ay magkakaroon ng text na magpapakita
ng Success.
7. Magtest ng isang
RecyclerView
Ang mga
RecyclerViewActions
ay ang class na nagpapakita ng isang pangkat ng API upang
magamit sa isang RecyclerView
. Ang RecyclerViewActions
ay bahagi ng hiwalay na
artefact sa loob ng espresso-contrib
artifact, na dapat ring maidagdag sa
build.gradle:
1 |
androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:3.0.2' |
Tandaan na ang
artefact na ito ay naglalaman din ng API para sa pagUI test ng navigation
drawer tungo sa DrawerActions
at DrawerMatchers
.
1 |
@RunWith(AndroidJUnit4::class) |
2 |
class MyListActivityTest { |
3 |
// ...
|
4 |
@Test
|
5 |
fun clickItem() { |
6 |
onView(withId(R.id.rv)) |
7 |
.perform(RecyclerViewActions |
8 |
.actionOnItemAtPosition<RandomAdapter.ViewHolder>(0, ViewActions.click())) |
9 |
|
10 |
}
|
11 |
}
|
Para makapindot ng isang bagay sa kahit na anong posisyon sa RecyclerView
, tatawagin natin ang actionOnItemAtPosition()
. Kailangan natin itong bigyan ng isang tipo ng item. Sa kaso natin,
ang item ay ang ViewHolder
class sa loob ng ating RandomAdapter
. Ang paraan na
ito ay kumukuha ng dalawang parameters; ang una ay ang posisyon, at ang
pangalawa ay ang action (ViewActions.click()
).
Ang iba pang
RecyclerViewActions
na maaaring gawin ay ang:
-
actionOnHolderItem()
: gumagawa ng isangViewAction
sa isang view na tinugmaan ngviewHolderMatcher
. Hinahayaan tayo nito na itugma ito sa kung anong nasa loob ngViewHolder
kaysa sa position. -
scrollToPosition()
: nagbabalik ng isangViewAction
na naghahanap ng posisyon saRecyclerView
.
Susunod (kapag
ang “add note screen” ay nabuksan na), ipapasok natin ang ating note text at
ise-save ang note. Hindi natin kailangang maghintay para sa bagong screen na
magbukas-gagawin na ito ng Espresso para sa atin. Magaantay ito hanggang
mahanap ang isang View na may id na R.id.add_note_title
.
8. Pag-test ng Intents
Iginagawa tayo ng
Espresso ng isa pang artifact na may pangalang espresso-intents
para sa pagtest
ng intents. Ang artifact na ito ay isa lamang karahdagang extension sa Espresso
na nakatutok sa pagvalidate at pagmock ng Intents. Tignan natin ang halimbawa.
Una, kailangan
nating kunin ang espresso-intents
library sa ating project.
1 |
androidTestImplementation 'com.android.support.test.espresso:espresso-intents:3.0.2' |
1 |
import android.support.test.espresso.intent.rule.IntentsTestRule |
2 |
import android.support.test.runner.AndroidJUnit4 |
3 |
import org.junit.Rule |
4 |
import org.junit.runner.RunWith |
5 |
|
6 |
@RunWith(AndroidJUnit4::class) |
7 |
class PickContactActivityTest { |
8 |
|
9 |
@Rule
|
10 |
@JvmField
|
11 |
var intentRule = IntentsTestRule<PickContactActivity>( |
12 |
PickContactActivity::class.java |
13 |
)
|
14 |
}
|
Pinapahaba ng IntentsTestRule
ang ActivityTestRUle
, kaya pareho ang kanilang behaviour. Narito ang sinasabi ng doc:
Ang class na ito ay isang extension ngActivityTestRule
, na nagi-initialize ng Espresso-Intents bago ang bawat test na naka-annotate ngTes
t at nagpapakawala ng Espresso-Intents pagkatapos ang bawat pagpapagana. Ang Activity ay wawakasan pagkatapos ng bawat test at ang rule na ito ay maaaring gamitin sa parehong paraan ngActivityTestRule
.
Ang
pinakamalaking pinagkaibang tampok ay mayroon itong karagdagang functionalities
para sa pagtest ng startActivity()
at startActivityForResult()
na may mga mocks
at stubs.
Ngayon ay
magtetest tayo ng isang scenario kung saan ang isang user ay pipindot ng
(R.id.btn_select_contact
) sa screen para pumili ng contact mula sa listahan ng
contact ng phone.
1 |
// ...
|
2 |
@Test
|
3 |
fun stubPick() { |
4 |
var result = Instrumentation.ActivityResult(Activity.RESULT_OK, Intent(null, |
5 |
ContactsContract.Contacts.CONTENT_URI)) |
6 |
|
7 |
intending(hasAction(Intent.ACTION_PICK)).respondWith(result) |
8 |
|
9 |
onView(withId(R.id.btn_select_contact)).perform(click()) |
10 |
|
11 |
intended(allOf( |
12 |
toPackage("com.google.android.contacts"), |
13 |
hasAction(Intent.ACTION_PICK), |
14 |
hasData(ContactsContract.Contacts.CONTENT_URI))) |
15 |
|
16 |
//...
|
17 |
}
|
Dito ay gagamit
tayo ng intending()
mula sa espresso-intents
library upang magset up ng isang
stub na may isang mock response mula sa ating ACTION_PACK
request. Narito ang
mangyayari sa PickContactActivity.kt kapag ang user ay pipindutin ang buton na
may id na R.id.btn_select_contact
upang pumili ng contact.
1 |
fun pickContact(v: View) |
2 |
val i = Intent(Intent.ACTION_PICK, |
3 |
ContactsContract.Contacts.CONTENT_URI) |
4 |
startActivityForResult(i, PICK_REQUEST) |
5 |
}
|
Ang intending()
ay kumukupkop ng isang Matcher
na nagtutugma ng intents kung saan dapat ay
mayroong stubbed response. Sa madaling salita, ang Matcher
ay kinikilala kung aling
request ang gusto mong i-stub. Sa sarili nating
kaso, ginagamit natin ang hasAction()
(isang helper method sa IntentMAtchers
)
para mahanap ang ating ACTION_PICK
na request. Pagkatapos ay
tatawagin natin ang respondWith()
, na nagtatakda ng resulta para sa
onActivityResult()
. Sa kaso natin, ang resulta ay mayroong Activity.RESULT_OK
,
na sinisimulate ang pagpili ng user ng isang contact mula sa listahan.
Susunod ay
isisimulate natin ang pagpindot sa select contact, na tatawag sa
startActivityForResult()
. Tandaan na ang ating stub ay ang nagpadala ng mock
response sa onActivityResult()
.
Panghuli,
gagamiyin natin ang intended()
helper method para mavalidate na ang mga
pagtawag sa startActivity()
at startActivityForResult()
ay ginawa gamit ang
tamang impormasyon.
Konklusyon
Sa pagtuturong ito, natutunan ninyo kung papaano madaling gamitin ang Espresso testing framework sa iyong Android Studio project para mai-automate ang daloy ng iyong pagtetest.
Higit kong nirerekomenda na tignan ang opisyal na dokumentasyon para mas matutunan ang tungkol sa pagsulat ng UI tests gamit ang Espresso.