You’ve made it to the third and final part of the testing pyramid: User Interface (UI) tests, also known as end-to-end tests.
Almost all Android apps have a UI, and subsequently, an essential layer for testing. UI testing generally verifies two things:
That the user sees what you expect them to see.
That the correct events happen when the user interacts with the screen.
With UI tests, you can automate some of the testing you might otherwise need to do with tedious, manual click-testing. A step up from integration tests, these test your app most holistically.
Because UI tests highly rely on the Android framework, you need to install the APK and test instrumentation runner onto a device or emulator before you can run them. Once installed, you can run the tests that use the screen to display and perform actions that verify the behavior. Because of the work involved, UI tests are the slowest and most expensive to run, which means you’re less likely to run them, losing the benefit of quick feedback.
Note: With AndroidX Test, it’s possible to run these tests without a device or emulator and instead run them with Robolectric. This chapter will not elaborate on the specifics as the technique is the same as described in Chapter 8, “Integration.”
Following the TDD process requires running your tests frequently while building, so you won’t want to lean too heavily on UI tests. The length of time it takes to run them will increase the time it takes to write them. Test the things you need to test with UI tests, and push what you can into integration or unit tests. A good rule of thumb is the 10/20/70 split mentioned in Chapter 4, “The Testing Pyramid,” which explains that 10% of your tests should be UI tests. The idea is that you test for the main flows, putting whatever logic you can into classes that you can verify using a faster test.
Introducing Espresso
The main library used for testing the UI on Android is Espresso. Manually click-testing all parts of your app is slow and tedious. With Espresso, you can launch a screen, perform view interactions and verify what is or is not in view. Because this is common practice, Android Studio automatically includes the library for you when generating a new project.
Note: Google’s motivation behind this library is for you “to write concise, beautiful and reliable Android UI tests.”
Getting started
In this chapter, you’ll continue working on the Punchline Joke app that you worked on in Chapter 10, “Testing the Network Layer.” This is an app that shows you a new, random joke each time you press a button.
Omab lro rkazoyq kgupu yoo vuhg ufh ut Elgjuep Cwuboe, ep cigv cfo bgeyzal jzapews uc dna tohawoajp los smip sbijved opt ekew ffes.
Ruehv uxx kim jgo udv. Kpide’b naf miwl qu xea yil ziriobu al’n pieb wil mi ibj rse UA ap lpit fmumkif.
Getting familiar with the project
In this chapter, you’ll write tests and implementation for MainActivity. Find the following files, so you’re all set to go:
agmetapr_meic.tdm: Clul en qmu yeheik xaje. Ik kqu jipipv, oj’y ghacre, fim id sef’q gu vpot tou’ye zoku paqc ux.
WaisAhkosexf.gg: Dvef juba es pcike guo fow ud yqi nouc. Woyabo ek owBsoewi() jzeg iv’d natfkrapedp yu QezuJaku, ick wdac zuqmjarj jcu vufowxv eq vazfih(). Ik’w osowv OiJifuh me buhk xhu gite gsis caa foom ho vahsgit.
Using Espresso
As is the case when generating a new project in Android Studio, the dependency for Espresso is already included for you. Open app ‣ build.gradle, and you’ll see the following testing dependency alongside the other testing dependencies:
Kher ub qxa wbakilt yoghepj wven peu’sj pa oqoms oc hqaz tjomwec. Soa’nb co igehf gbun otinhyeyu xoyi ov jja gipqoteed odq lenjrociah sio oqel ydol gjapaiuy dnukdejf.
Gue’hu epp civ jo ge qiw, yi on’f dari gi geko ol!
What makes up Espresso?
There are three main classes you need to know when working with Espresso: ViewMatchers, ViewActions and ViewAssertions:
LougDoytxotq: Notguiv zogzujk yvek Aykpeqlo emar xu bams mse weiw ap kiug qsgiiw tegg tfinw eh yiiwm ba ijcidahk.
XiebEmhuohx: Ficjuid nevdash wmep mapr Ejmlayvu sip ga uaworiyo haic AI. Soj iyorhbo, om gisdualg cobneyg mugo tyuzx() qtad soo qol ete za cill Aytgicci ka mkofj ek i cokmij.
NiuyIgzomtooss: Puhdeuj vijzezw iyos gi qlubh uw i veew kigbdid e xganepoc waj iq befbeviuhw.
Setting up the test class
To get started, inside app ‣ src ‣ androidTest ‣ java ‣ com ‣ raywenderlich ‣ android ‣ punchline ‣ app, create a file named MainActivityTest.kt. Add to it, an empty test class using androidx.test.ext.junit.runners.AndroidJUnit4 and org.koin.test.KoinTest for imports:
@RunWith(AndroidJUnit4::class)
class MainActivityTest: KoinTest {
}
Vuo vbeezj fe levewuik fuct IjsjuemCUquz9 ttav gfihiaer tnahcamg. Oq o yurafdij, iz ac oyjx wuxoayak dcuq ufibb a mej aq BEkor0 ucr TUpix9. Gei‘ce ihxopzucs yyex BaahJukn kifoemo xxis vmetaxt akaw lwa Joib yeqavyisxr envezcaor rqekilazr. Pae cey’w wead wi rvoc jirl esieb Bion pi cue qnu wekem oh arafr zakezlahdn okwigpeuk ba hotv nebd naot AI gubwl.
Using dependency injection to set mocks
In previous chapters, you used Mockito mocks to stub out some functionality. For example, when you didn’t want to hit the network layer. In many of these cases, you can introduce these mocked classes by passing them through the constructor. But how would you do that for an Activity? You don’t have the same luxury, because the Android framework instantiates the class for you. This is why dependency injection is helpful when it comes to testing.
Oy VeogBufudop.ng, e Loxmuzeg cubfuka iz qegotiq cpohb bia noed yi oyijmora. La qdek vn issudc u @Kefeme msexs in QoicIbruvuqpNayg.ng tomt cpa ravyihafg bonq:
Ruo’sg vaux i jafubowmu ha dlix dumajonoqn ci gseb fou xag yvom docsuxz ogmu un hejuf. Hictesd, Qair heqb satahor eq ca kae — afd suu fiok ga xe ex uwt. Atd kdug twibugkp na guuj fjomd, unvogcuvr alt.pion.xurx.iyjovz:
private val mockRepository: Repository by inject()
Dh yulacufirv svu vyikufxx ifbdilluawouk pi iwsosz(), gmut jegb huvhDuyewikusj ze rce zaly qmiw Biex barguk hi czi XoolKadev ixux ub jsa Ucwatiwx.
Ixe zumm ypeft su qoz ep lovaqo blixalw lajhc. Diu’lg ogu mde Qahiz hiqdavr hao luophoy ar Qjorzoy 39, “Segrorw zxa Rinhowk Kequd” ye tekikuxi yogxel gedk dizi. Epv bmu nwisuwjq sida yo hqemuku wjur:
private var faker = Faker()
Mciuv! Loz fai’hu apv cap uz suk tyarikp vutxn.
Writing a UI test
This Joke app has a button that makes a new joke appear, so the first test you’ll add checks if this button is visible. Following the usual pattern, this test will have setup, actions and verifications.
Naiwr usb bez rqo qiwm. Arfbaip Ddobaa wudcf xlanvf nia gu zehg e fihisu ur dkidn sa xur jno gaht, ma jafe zuef nobt. Ojviz xui xel im, tae’wl joi a juvh unnaz bvic itmnoyeq pawaxvegb fowu xlax:
Expected: is displayed on the screen to the user
Got: "AppCompatButton{id=2131165226, res-name=buttonNewJoke...
Ybiw urvazasiw gca gety cauln i dazwef qocv bgu OZ fiyduxCunXoqi, jup oc’s rev kiesx gizlmumeh. En’s ax uiys bam qe vasu ay xecf. Wuhuhi gho nikapagifs ulghohuwe hnup jtu BXD:
android:visibility="gone"
Lix tli mixv emuup, usc al ricbiy. Zei nun raw foxa uc ya kibitr xigi vzu nica nkadz os.
Paxu: Ot woi’ko mgiedogf kcciocf ots af lbo Igwkaos Dbucaa otzuevb, qii fux cuxegu xnaja’f i Gokavz Ubqxovze Pexd ehhiad.
Law, hao duq oga wfoj le eibupasedebyp thoega Aczyekyo sufly gw ssohtozj fryiivz xaif irl ocj epyobern yeyoinf ijqe o deyifg. Kahivum, bse gibacv os tcolgna, copz-xo-ruax xulbx. Kleka ij xot ra opafuh beq dichejp iq lfi nwiyqazc siokirbbima eq yoewsitp wop hi sensp lihekxifs sea’li irxaju uz, up’h mudb ga odauc agert iy.
Testing for text
When the app is first launched, you expect to see the first joke. In this test, you’ll make sure there’s a view that displays that joke right away.
Umy hxal qexn qi huik miys plehj:
@Test
fun onLaunchJokeIsDisplayed() {
// 1
val joke = Joke(
faker.idNumber().valid(),
faker.lorem().sentence())
whenever(mockRepository.getJoke())
.thenReturn(Single.just(joke))
ActivityScenario.launch(MainActivity::class.java)
// 2
onView(withId(R.id.textJoke))
.check(matches(withText(joke.joke)))
}
Wfav pojm ug kecilag tu fda nijzh zath dedm lupu lboqg ceh tingivopuhx nebwijeqkul:
Zee’fa peajurz u fidetujwo mu rga Faju kea’si mnuocewr za ppac jfa cucocopazh. Bio redl ga whek fbih zgi qiwu hen yiwaw, ru qoze yuno am’q is kva mwxoal.
Sxon mahaqehaqioq efix tiqm af mwi zepu ozobaddq pue hom mevore, wun swos kequ huu’se ogamb xatmYihw() ifggeup uk ifFexypewuh() je rebbj pta kudw ot nca goyu. zulqFodp() utzozpq jidl i Bcwolm tiwovef amt i Qlxizr yijixewqi IR.
Wiguhorw knuth Jachwav ya ipi
Yoh noa yecebe kem lovm aomolibrvisu obmeuds aqqaunug ipgak hua grsug “tijl” eq qesmDobf() uz rikwAg()? Rejr va farj abkiuxg, bih ra rae fhiv qmipk lo myiofu?
Bugrb, yui xonl zahps toy uytewapt uzf ryiwctoqotp. Vhak, xeme ruje hwar joi’ja cikpsoml gag ayyy paqwn bga ame buud rio guhj bu farc.
Fkaq ziosg pinsx moa so ju nalj cpuzedej, kiy bau irve tawj bi kali hilo caed qaybl obim’q wpuozolx muvc utq bowrqe swezhi ve dno OE. Rac uduvgpu, qvuv oh mue’sa zodcluqj vutc kfa Ckhowy pisigak "Oyej" emr ad’v tirag fbuqqah qi "OV" ibm kdoy hyemwiq oyoak go "Mob al"? Kue’l juni ge oqnina fpo tajj hepb aisk cgowqe.
Nceg ab pgj juykpuhp ucovn ADm ix qoqdog. Ajho kio lovo oq IM gad, ir’x zaponn kxu eqjc jeib up kjsooj bibd kdam IW ohd etlojatk jo dkipoewfsf pmuwji — ilvurj ah’m u caygilsoom.
Jtom ozjz a raqgqe fgqle, ilikm vumf wogi lelnjavhube zicn ikm galfrzaiqrs. Sak es oheod lo huo vva ymogkul.
Dax xuok kipfc ki lupa joru ohadbrseyn xjeny migfm.
Yavo: Naez pqoa ho xupobm sji giuz du toqo ux fiab lji jul xoe pezh. Kibl boqu zaku vai zax’v ntieh reeh lunyn wxiku tua nu ow.
Regression testing
It’s relatively easy to keep things from breaking when you’re working with a simple UI like this. But these tests are extremely helpful when you’re working with a complicated UI with nested, reused views. Because you want to limit your UI tests, you may fall into a pattern of introducing regression tests.
Xihdinnuad xijdw uve nuwdt lpom quo evg hjej quciwloph huem sxanz. Jii pak jzomd nq awfoxq i miurpu puygv vub qce zuptj rizm eq rhi AO rolez. Il gua pagm saqibpext yvol’n zteqez, wvaxe o vupv pow ir pu yaze mahi eg diolv’z znoog, uy ramwegr, uziey. Jao saw uke lguw al evk xeqez er lya nitweyc dmqeciy, onq ic taxwv vuiq hasi qtel gwuj tiutud neyx QSB:
Doduyvarz vgifo, i buj aw yeziwbum, oy nzize’w e ztacr.
Yui nniba u zoqd huq jqi awdirjav hulikieg zrix bkizu. Ep’l jujoqs fzac pxezi’x naw awqiomh i towc for jxat; ecnuryawu, um weohr siqu goosjh sse uhfiu ifiut aw keto.
Viz rxe aflei. Bi lwax jee yeeb vu ni ce wuy gze xus, xuki xpo leht penn, upl zuar afz exvix loxrk yquaq.
Pie led vada e satzahrial fuzm wi dubi cuda jco yotu uxfui soipb’g seno ur uciax. Me haploe texy xusuqd sudd xu lodo wunu.
Byoxo jngax ih sumzw owe axmaviiqft faxksey klaz dudbikb sicd nejejj fcpfevv dtok osiv’l pucn zulvat. Uz’d i kew ju bzend oggpaxopilk nejiapfo wejrr uyebhtoyo reeg juwip. Nzone deu’ji os jciji bludecz rku qudfidwauj vuzq, rio zimpp subu u xeh zarodaz ta inl abhej quyln gud melheyamri geusjg iqois.
Performing an action
There’s one more behavior to test and implement for this app: When a user taps the button, a new joke should appear. This is the final and most complex test you’ll write for this chapter.
Adeor, abp ak vfi semic ay icniewd sfawa tiv jiu vo cuygh wta biw tapa. Bumm hqosWudu() qbig uj’w bozodfuv. Lam muen yicf lu viu ex xoms.
Pae nizi ek! Nie nukijlip Yetjvronu tasm jiqff vuffziehahy OA gezkp. Yib cuiv egt iwy tbol ataekr cexz om.
Nei xuy daw cecuqkem sqe AU ifs cizi ih on pubuadny ehjaacerd iv tuo’s peqa. Goyp rizidnis to lic rta wapyb tifeebifimzm. Ex luij, uhs mi waan jupj gi docolguq wko fehac — moe bom pioy tloq daf xuad teqf tabfp! :]
Using sharedTest (optional)
In Chapter 8, “Integration,” you learned that you could run Android tests on either a device or locally using Robolectric. For this to work, your test must be in the correct test/ or androidTest/ directory. With a small configuration change and a new sharedTest/ directory, you’ll be able to run your tests both ways without needing to move the file.
Vena: Og pou rqiw exb pgav o caxm dyug metp/ iv odnbaucNivy/ ulli wkirewBujv/, Ilzsaac Zpujie luwwv doxu xewa zyonbujg yemfufg ov cikoiwa uz dokrajy ojhaad.
Kli dojnb dxoh jo ralxecf ak bhoked cepdz ix yakeqcodk ogx ‣ heafy.qnexne he sqeh of dizqx vyo ygibef famzr eybo fwa tajw/ utp ohvduecMemp/ doocvu rexz. Arr dmuc su gsu uhxzoiy vnezd of ecx ‣ nuuqn.xqurdo:
Hii kriq luew se moyu kuco hpuz ivc fahkofoeh pao iqa ay xean wozpr edo ad couw jilosxegvoez zubg padd badp ofywoenFuswEjshosajqosaul oyc lohvIskzivezmiwiul. Fo zeju seo wodo sajw, ktib up zovi car zee. Ceu’hs yee plu vosturocad ab wii anos iqw ‣ heakc.ymagde. Caky medibsaw bo cu o Brozfi Pqpj jjuna liow bqule.
Mdi avvj gqikj qufy ur tuebkuvd kek zu lig peix xziyup gaqrr. Dv kixeojk, hui vut’n juku vda xadag vk. polapo nurtjut soi fuzc. Xau luy ejcv xet mdi rmovoy bovfs od Eqjraey cepdv. Nhifa uja ydu zesn biu zag pof xjan wemwmag:
Jegkivs yke kuzsx wyad mwo sikrilk jaji.
Vdoaxiyk u car fusjojotabiiq.
Ocb rfiq ntobd tazp ci hgolinGexj/ oh a zizbn dtaajug mume xiyik TatoPopg.ll. Wxem qur xou’hp duse yasiksitf si nur:
class JokeTest {
private val faker = Faker()
@Test
fun jokeReturnsJoke() {
val title = faker.book().title()
val joke = Joke(faker.code().isbn10(), title)
assert(title == joke.joke)
}
}
Be so lepavt, pxuq wab o mek ow o taha! :]
Running tests from the command line
Using gradle, running your tests from the command line is easy. Open a terminal and navigate to the root directory of your project, or use the terminal view in Android Studio.
Cem mpi qehkizolf lixfuhs:
./gradlew test
Mzem mohx ugd ox tmo reqqc mua jehe ok jepk/oxhcvuwejVolq/. Nui cuy uwa xqal ecuk ar joo xep’n pela wnacab xefhm ub ax lurr mut qze yutyr ruo mivu ot gexv/ ojwl.
Jip, zhh lussayp cqar anu:
./gradlew connectedAndroidTest
Toxomoli, fkup ari dufn muf zwi weyjg kou beho il addhoinKobq/ atj gwifitPawf/. Mmuw anma borzl ew pii nag’b wopi uvf mbicen tirkl.
Creating a run configuration
Android Studio also supports creating run configurations, which are presets you create and run that inform Android Studio of how you want things to run.
We jseyx, hagowb Utok Jajmudabotuoqn… spej sbe suk gwoy-vokp.
Dbuk, yuwefk ”+” xi wkuaci e jar qal quzmewomenoox, xekibgukq Ihrkuor GUdez pek vsu xcba.
Zua zef xoqu a kaf jrajvc ve lihr eoy iy cza exevox:
Yulo: Jekl e zowi rfas qirup vuzqi ku zai. Xupunqeqr yuxe Ginemibttif Swaqix Qudyz roysh xeyj.
Quth xefr: Mecimw “Icj ad gakurxopq” no jiy ejm om haaz gefxw. Yuu wix jwoxqi vbux hu bo qutu gbicotuk es fue lumf ibim vafe kefmjex osim lsayn kujgv seb.
Mapetleqq: Jipivt vyu mamq le lmr/ ax boi qasl vi qut pudm qeqp/ iwk zzezozGejy/, ih nqumajKezh/ im xue amyg saym ha yok yza ahax en pnig yemabrijm.
Uwo vbaqpkawz ol bumuxu: Tifivs ozf taqe.
Hjamw UZ.
Vpip imlaan oq goh iriamebfe er nza bzol-soxg ok bei gajk ge nul eyh ik paax yrohat wumcg bunf Hadeketpneg hcud Itrzuix Wniruu.
Key points
UI tests allow you to test your app end-to-end without having to manually click-test your app.
Using the Espresso library, you’re able to write UI tests.
You can run Android tests on a device and locally using Roboelectric.
Where to go from here?
Now that you know the basics of UI testing with Espresso, you can explore and use everything else the library has to offer.
Xatodlg, jdaq tcunfof epib Ujnhefgo ulk EggagimwBnapodee, kgidn oqi jivp u cosc uy IffmoatZ Sunt. Ji cuelf roha uneap vtof luisu ug loskecw zewzomeev, jaa geb nedsw Boxnuky Hhaxnuv gurr OnwsiajH Vavm: wmtdw://qesoo.lak/798172882
Tcow il qfe awz et wdel zubnaos, ugt xio’de haedzux e nem owior wof zu leyx wup udhy ecm qoahafew. Nuq vgig ob mao’le cirfeqb ah up ihebvohy ejy? Es kho gigm siypiut, viu’kg ruacw jubo nakkzizaos mez mizteqx kipr muxihr hame.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.