Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Android SDK
Code

Ang Pag-test sa Android User Interfaces Gamit Ang Espresso

by
Difficulty:IntermediateLength:LongLanguages:

Tagalog (Wikang Tagalog) translation by Anna Nelson (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:

  1. Ilunsad ang app.
  2. Tumungo sa login screen.
  3. Kumpirmahin kung ang mga usernameEditText at passwordEditText ay visible.
  4. I-type ang username at passwords sa kanilang mga nakalaang fields.
  5. Kumpirmahin kung ang pindutan para sa login ay kita rin, pagkatapos ay pindutin ang login button na iyon.
  6. 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:

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.

Create Android Project dialog

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)

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:

MainActivity layout

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.

Create new test dialog

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)

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.

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 o Button) 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.

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 ng TextView ayon sa text property value nito.
  • withHint(): nagbabalik ng isang matcher na nagtutugma ng TextView ay base sa hint property value
  • withTagKey(): nagbabalik ng isang matcher na nagtutugma ng View ay base sa tag keys.
  • withTagValue(): nagbabalik ng isang matcher na nagtutugma ng View ay base sa tag property values.

Una, i-test natin para makita kung ang pindutan ay talagang naipapakita sa screen.

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 Views 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 ng Views na kasalukuyang may focus.
  • isChecked(): nagbabalik ng isang matcher na nagtutugma ng na tumatanggap lang kapag ang view ay isang CompoundButton (o isang subtype ng) at nasa checked na state. Ang kabaliktaran ng method na ito ay ang isNotChecked().
  • isSelected(): nagbabalik ng isang matcher na nagtutugma ng Views 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.

MainActivityTest class

Yehey! Pumasa ang ating test!

Android Studio test result toolbar

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.

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 isang EditText
  • clearText() para i-simulate ang pagbura ng text sa isang EditText.
  • doubleClick() para mag-simulate ng pag-double-click ng isang View.
  • longClick() para gayahin ang pagpindot ng matagal sa isang View.
  • scrollTo() para mai-simulate ang pagscroll sa isang ScrollView tungo sa isang tiyak na View na nakikita.
  • swipeLeft() para i-simulate ang pag-swipe mula kanan pakaliwa sa kabila ng patayong center ng isang View.

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.

Sa loob ng layout file ng LoginActivity, bukod sa EditTexts 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!

Android Studio test result toolbar

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:

  1. Inilunsad ang MainActivity gamit ang activityRule na field.
  2. Siniguro kung ang pindutan ng Login (R.id.btn_login) ay nakikita (isDisplayed()) sa user.
  3. Nagsimulate ng isang click action (click()) sa pindutan na iyon.
  4. Pinatunayan kung ang LoginActivity ay naipakita sa user sa pamamagitan ng pagcheck kung ang isang TextView na may id na R.id.tv_login sa LoginActivity 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:

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.

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:

Tandaan na ang artefact na ito ay naglalaman din ng API para sa pagUI test ng navigation drawer tungo sa DrawerActions at DrawerMatchers

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 isang ViewAction sa isang view na tinugmaan ng viewHolderMatcher. Hinahayaan tayo nito na itugma ito sa kung anong nasa loob ng ViewHolder kaysa sa position.
  • scrollToPosition(): nagbabalik ng isang ViewAction na naghahanap ng posisyon sa RecyclerView.

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. 

Pinapahaba ng IntentsTestRule ang ActivityTestRUle, kaya pareho ang kanilang behaviour. Narito ang sinasabi ng doc:

Ang class na ito ay isang extension ng ActivityTestRule, na nagi-initialize ng Espresso-Intents bago ang bawat test na naka-annotate ng Test 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 ng ActivityTestRule.

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.

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.

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.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.