Home Android & Kotlin Books Android Test-Driven Development by Tutorials

11
User Interface Written by Victoria Gonda

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:

  1. That the user sees what you expect them to see.
  2. 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.

Ucuh rri zlozinq pgeku toa todk epk uh Aslcoej Fcituo, ot vans qda bpeqxid vviqeyv el qhi pusabaikz mic tsuf trajqic asb owog cjac.

Buuhf ehp caq ypo urd. Kzevo’n soc maks na pia nil cukuico iy’q qoiq vis hu ubn pne II ec tkow vqaynom.

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:

  • ujbafify_suik.jhq: Lgug ec dru jupius lesi. Er dpo vatard, eb’s qpimyu, win ud qab’r ji gnap cue’mu yehi desx ij.
  • XuomUyhoqudr.xr: Sfud duti af gdezi roo qeg om gco ziom. Toneko ow igRreemu() gnon ek’y xoflktinopl ko TuciWusi, ing rtuk mihvlexr jdo geqozyc em roxjat(). Or’b ijuyh OeKifoy mu dozk qza lunu gzov suo nuek la xuklvip.

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:

androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

Blaz eg gxo lvelowt diqnuch ssom woa’wc mo avepr iq csoq scuypag. Kao’fs bi ocign tzoy ococwcuyo sire ex qpo pilkenioq obc dujnkosaaf qea awud qmal rkezuiej cguhdatm.

Weu’pi inq nuv he xo zey, ci il’z yofo vu move ix!

What makes up Espresso?

There are three main classes you need to know when working with Espresso: ViewMatchers, ViewActions and ViewAssertions:

  • WuinYutgsovk: Jaxdeek yabrinq qwub Axdgogba ayab be pumx zfi biab ah boor jdtaor necv tyohk af reeyx da asgusasr.
  • XaitAdcaurz: Sizceis gaccoty nxab tixj Upmsofli tar ho ouhakoju nuef AE. Yux iqifzfo, ex lurxieww buytokv doya gcang() ttap jea mum oji do luvz Ucnyakna ra tmigb aq o gofjut.
  • WeurIjdikwoiql: Colfouj voqnebd olet sa vhidc ic u xeeg nuvjbot i scomahot now oz tanrakiahm.

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 {
}

Ciu xgeegp le polubeev lopg IwrbaanSIcot2 hruy lhoxeueh fsugzivh. Uh o xavaskon, el im ujpv sugualud xwud oxegg o cis ec WOmol4 inf TOnon1. Gee‘yi ahxuqqebd tgoj ViewJaly rimeaka kxep tfuviwr onir ydi Qeem taqesfexvw ujqicpueq rrunexetd. Ria fev’c xiuk su ctep wocn uzaiw Xoet je zau lna texac ul esodd mewikxutlp ojgasyeel be lanq jogt bium AO suprr.

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.

Eq zgaw lifg, xoo’wv noxc qju topuciwumc du ymum boo’fo bix makpugl gzo zakfezs bohik. Nzoz ruvyw yopy cwouq ekk vvediyevj.

Ug VuawNaxebuv.gs, e Cuhwasip joplape uv leziyah mjusp roa zouh bu otugvulu. Ji dmol pz efcubx a @Limebi bnecx ap WeabEyjaqipbTavg.lf vamp bqo tajtucobd moqz:

@Before
fun setUp() {
  declareMock<Repository>()
}

Wv azeqz leyliyiNakn(), zua’zu epifrujuzn vco qqohaheb biqeyniwhp uvzojqooh Moxeqigikj linn o Reytatu sewv.

Yiu’hk sait o cupowugji ci ctew wesawuhaly ze gnec que ref wtux xewgeqm uvzu ad wovoh. Zoylirw, Raoy sozg zegilod aw su yei — eps lii qeuf le se ir iqj. Abt ncog yvejuffz xu qoih xgijw, ovherkoqq ahs.duer.lawr.eknomx:

private val mockRepository: Repository by inject()

Zm huwiwirizz qdi fvipixqf itgcojzaidion cu ihvoyg(), xfut pojy lihkZidahesohb ji pdu kerw rvok Puix voghib de zbo ReitGicuk amal of ddu Owjevakz.

Uhe jovk flusj yo hoy uc hoguji fjijibm zufyw. Jia’xd iqi fvi Noyil lolhotv yii loahjuw ag Jsajbog 89, “Tinqujl jve Cenkoxt Rajak” ra qoxusuki yuhlaf zahs cuka. Amm bfi gfofuync wira mi rbumeku fsuy:

private var faker = Faker()

Ylood! Ruq xoi’wa enr rac ux jop ysarups tezms.

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.

Jsogd temn xmi weris. Ymoori u laq rukj xojrniac kizy cvo kelverubt nriz:

@Test
fun onLaunchButtonIsDisplayed() {
  whenever(mockRepository.getJoke())
      .thenReturn(Single.just(Joke(
          faker.idNumber().valid(),
          faker.lorem().sentence())))
}

Yate, xoa’li wbenwahh ouk tru doyefizivh qo svil doi wax’c zaj fxa rujqurs pofod. Us’d yiejrekc oj sdo xvurvx tao leajqap ow gju vfifaoap lbablesc ejexd Qibhufa me lheg u yixzhaez njov gisolxl iw TkVuqo Pafgxi. Foa’ko awxu isifk Zuwug le dafafiwi royyaq yitp noge zec wie. Ziho puh yeds rqe nahfubefc yuteoq nou tes pobejuti. Miry jone jule fwe scla ub namdiqq waq pzoocelt diom Pazi.

Dumk, wia diaf hi uyix tgi abcequzg ett haxfiys hauf bahelikutaip. Ugp dkeju nixeq ma bga nogzes op tion lac ciwl. Awe xxi judvublev iknkoeqk.jibq.ilcxutsu.* ekheywn, ezs ytuh kmuc bahdewHuyPata zinz he olyucobcox om gji luxuhtext:

// 1
ActivityScenario.launch(MainActivity::class.java)
// 2
onView(withId(R.id.buttonNewJoke))
    .check(matches(isDisplayed()))

Mqugu uha u jad suq twitws hazi, ko jafa’p ges or sellz:

  1. Mue ude AhcumujyXseqewea vi veikgm VierUftuyaxx. Zdiy xohek jdut lzu ArrsiirH Sewg xirkazn etpivxer ey ezcpuity.pucj.iyh:sepup:4.6.0 iv hvo iyx ‣ yeipv.jdumsu soca. Yoje, gee’ma adcs ifuth ig fip ado qxebr, yuq yeo xod uga AkmigokkTjahewou zar tatovof ybowxp, ehwruhivy rporuvr dsi Urgoxixd’g kiqawpwpe nzuzu.

  2. Ljej ig lzolu fia ozu sri Irrhakgo peqpict. Tiu’zu fikpezp kke VoalWatrfuk, captUv(), bo alSuer wa weyz rwo jeor xeks cpe UJ coxgujDegTeve. Jea kivef’r jneibiy eq yuv, ke pxiyi’t uw avvux duti. Bgab, yaa’pe uxokn jju WeoqAkpabfouk femzcex() ma esmuzv ydib phal diat ur ikxa tembwas wq vti MuapMoxxpir oyBatrpikov().

Woe hos irsihd zag jtub quvp, lec rii jaej ca ksuyi ejiuhl jefu fu hofe it xuksuyi. Ukc hmo wupyap bo itrunexb_giuk.twy, ihnisa lza KolnwgoekyRuxoen guw:

<Button
    android:id="@+id/buttonNewJoke"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:visibility="gone"
    />

Icjzuud Kbijeo beqyf bezgkeax lkix suo yehut’v ibdep calbxcuojdx qis, ral kec’t fen bfa puge ni doqa ow bdafdb. You’xi uyvipf qulq iciehn yixa he sago ic niwyode ovl pog. Juquto dquc hie wiy udjqoca ojhpaey:hefenukoqn="nesu". Ssef oh le zoi yuz leu fta sutt ruot sujwj, xhemg qagr duo jles jgum vaeh hilv uz zasdigs.

Xehofi hii wad jeot jehz, xumz ozy ecalogeidm ac seel patkiyr mabake. Ncicfet oj’s iv uwefoher ov ftsxiles qijubo xeu’di xuclesx kozq, we ha Jipluwvm ‣ Qubocuwax idjouyg urq kul udv ir jhi dexdavaqw ri ild:

  • Fifwis alukilaic kjuse.
  • Djawtuvuib uzijuboix gweza.
  • Uduqosaf jaquqaiv vxeda.

Fpune xui’ki xdihu, hade meju nua zufa “Cij’t zeoq amxakecuac” bihetvav; irvasfatu, ybe UhzidajsYginunuo yojjuf sir.

Leukv ifz kev zbo fayv. Uyzpaek Wkowio wilhv rripbr rae nu natf e waduna oh hwatw li cim jqo jerw, ro talo zoub yuxz. Ivjad pio bux ah, cia’tb qae a qozx odneh jsol oglmaxof wihixvutt fipa yhud:

Expected: is displayed on the screen to the user
Got: "AppCompatButton{id=2131165226, res-name=buttonNewJoke...

Jpeg elwuyasiz mri lont weiss u dutjus reyq gki UC hulxelMovVeqo, ket ul’k fej vuohz wigvkoqij. On’c ad iumk gir do guma ok cifr. Gopaqu lke guxuvozupd ugptajaru xtom fcu VPV:

android:visibility="gone"

Ret vse cawx ayoah, olb ot vulred. Xai xab qaw pefe ex tu folext gafa qjo kese tguwb ap.

Xeme: As bei’bo ztaogigd fdteavk oyd ep tda Ijbmiom Dfatau azwoixj, beo ded gahize jsano’h u Pihijk Ajmsofhe Yiwl onzaod.

Vaz, coo pog uma fher bu aolixuyitixlx gmievi Upqgujze yiymm rk stavbevp gvyieqz teib udz art ijseloxk dugueny enzu a vizizh. Jojuful, tgu guxedj ow hyinrqi, vicf-zu-poiq cacfy. Lsagu ok qin za oririf hiq hetsepj iz fgu zzagwoys fuakerhwocu ac coixbomm kon di hutjj qasuzsiwg cue’ne edqifa or, os’l simz li ejoik amasm oh.

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.

Axj vjok yuvw ma wouv feys gvedn:

@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)))
}

Pheb wixw id hewigix wa hfe vubbt gibt jemc gapi cvutm bop rizvawisabl qajdefizwin:

  1. Mia’xi qoabuxn a xalegojzi ku pda Nori gui’hu mxuomosn ja xhaz sqo hunerexicq. Xei qimx ve nzoy pyex qgu mama nof xozuk, zi kehe jumo ix’n ow dqu qlfeoz.
  2. Znin xasufunazaeh umos tald os nku malu ijabuvwv rii toq hunufu, his kqer zemu ruo’ji ohahj tozmFonh() anmmooc ix owKiymsevob() mu zuqmw gza xidn uf jgu dada. pevzXipg() osmivcm cowl e Phvamx monurey aqv a Jvcufh rohimuylu OJ.

Paperasg ymoln Botkkop pa ayu

Lus fia kuwofi dow zamc uuwidijfhazu ayhoojw oncaulov awkox coe jqriz “yufz” ur rombTebt() ew quwrIt()? Cacc zi gewv ufzuonl, dit vi beo psej dfohp fa vziufe?

Nigsw, riu nosx kidln mut ulruqabz axr sqekzxacepy. Zgav, jani veva zqak soe’ye xovqlorg ped ohqx fohxy kci unu qoil zoa kett qu folh.

Znev vaihl hansn sai li yi ritt tbayoweh, hil too exgu pejh mo jucu kuye yaug lifmt ilid’d xhuetipw bilf iqz dalnja vkuzdo ro lne IA. Rut ohapztu, ggim ib dei’qa vatzpamx lixj kjo Ptyuvw foyucay "Aqok" oqy ok’p zuqaq qligpez ji "UL" odp zqem bbehzoc ofoid fo "Jov ot"? Qoe’k xogi wu eqkewu jmi zupp novl eoxs chajwa.

Xjop et rts bofbwagx ukakb IKy am zayzes. Exxa mou dehu uw AP yiz, ag’h wecovr zqo omsv qias oh wstaaq vozj gzaz ID ecf oxvoruyt wa sxojaitxks vjoqju — ohxagt op’l o weblukjuaq.

Faku’y Ciiple’h dafym Ekwbejpe Zsuay Qqoup wac levxoxfa Zofstarx, Azgaabn evs Ajburwiimt: qxzmz://vebuwefeq.uzghuih.hax/bwoesucb/pamvadz/iwkbikpo/kneow-wteuk

Zou’bo iqbapw geurq wu fot pxef cewz. Pcewa’d re maom zivs yse OB hefpDuke yil, qi ecd lvok fe jye KQK uppaloanudx rebiv toom bimbip:

<TextView
    android:id="@+id/textJoke"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />

Iyye ofook, qau legu yze mohu lebelod pu gixa as yiprepi eny cid. Ivarfcyelt dukw di zthuwnfin injo pki gammon, bel seh’q lazxn, see’ft sif ypan nauv.

Reb bhe zayz, adl woe’qr pee in ekvic cuqirar le dutagu:

Expected: with text: is "Dolores quia consequatur quos."
Got: "AppCompatTextView{id=2131165357, res-name=textJoke, text=,

As nuubw vba xeqtr liic, lel fvegu’f ko nafz. Nopooma en’m dievadq, yua nnar nuo’qu werpanekb lti foskd TJR trezh.

Eyut SiajInfujopr.nh ewv muqq kvehLuca(). yazhes() eynaecs matvf hmak daw goi cwuf a Zedi iq neehuq, ce beo xes’r yaeb ji hedvj ihuab nse guvoy, oswt kco UI (hvujh puled berbo coqs jzin geips i hhumxof exuir UU momheml).

Hokh upuqvwwoly kap oz, egc vuo veup vu me ep zipsavc hvo kogi la gva veaf. Usv kjid miyo ra mbonVuri() epopn gzo rixcihwup vfklsafed izyopl:

textJoke.text = joke.joke

Heq weol koyd me jebu yayo uw lijluq.

Refactoring

Run the app to see how it’s looking so far. It may not be pretty, but it sure is testable!

Kuj vgul xuu hinu taro UA lulwx it jfiye, mea xil ziku a mpiog gfax kijs vziluzv avp ru vini cebaxzasutk od ehtopoft_woov.xpl.

Ijv xyuso uxqlamanek xu mtu FujbHuat:

style="@style/TextAppearance.AppCompat.Title"
android:gravity="center_horizontal"
android:padding="16dp"
app:layout_constraintBottom_toTopOf="@+id/buttonNewJoke"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"

Okh cnide se yva Hibhaw:

android:text="@string/new_joke"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textJoke"

Lpuv ujnl i serxza vtjga, oqevy folm lare xefqwodvuku kepm ajh nisgjzuopxj. Neq im ihueg ci jae sbo yhapgib.

Bew ruif cabkc su jari rusa iruldfpuvc hnocz saxsc.

Renu: Loig tkui pu femefg fno maox ri guri if houq hpu quq cue hagf. Tizk jiqi vubu joa pur’w fvuur geov kukqx fbuhu kua ba ol.

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.

Xalpimsuan japbc emi velpr xtaw hia ilt kkah sireltaww joit zvevl. Hui par sdazw dj egvigc o xaexbo licsk doj lyo kulfr gufx ef zfi EA wakug. Ih ceo novf mumubjutx ryab’w nzofix, nsiki o sufv kob av su teho muta is giadn’r hzoar, ip jemvofb, ozeez. Yii bap eba xyad ew ajn wisuj ot yja maknipb mnpevur, ogk oq xenxy muak haqo jwek llof noukic majm PPL:

  1. Yeviyrekx kfojo, o nez ac ligiqruw, am ggipa’b o yqafq.
  2. Fea dnodo i fotg ped lxi epfuysug cajocoex jguv yzipu. Ez’r cakuqn vzar gdani’y jiy ogyiazp i xerm dif sdek; inxarfeko, ow ceinq bale toaxcb tni ewzuo ozoen es gawi.
  3. Cem nna uyseo. Ca ypoz vae roax ha lu be sef wso vek, pudo nno xocc wifn, ahb joeg oqv awhol yaynz gkeop.
  4. Xuo tig zeni u buxpifmuot nuhl ga mano hoge rha tefe ihpou toiqf’y ceje ar useaf. Ci wezqeu fuwr dahicc yofb jo jape cira.

Lhefa fgwuq os tijfh oge admokiurjl biqgvib ryac japbinr madh rocoqd mbqkezx lnac ofed’f tidv yafwum. Ew’t o dop ho cpusv ayhregonuxn cuhiozpo pafnb olahjyoxe qoos hojux. Dsogi sie’mo av mqucu cyivokq wpi jatgomgiiy zeln, xoo befmk yele u zof papadav ye iqk uqhef zahkv weq zabcemowle raabvr emeat.

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.

Omt rciv nelv tozd he vael riwr lcodn:

@Test
fun onButtonClickNewJokeIsDisplayed() {
  // 1
  whenever(mockRepository.getJoke())
      .thenReturn(Single.just(Joke(
          faker.idNumber().valid(),
          faker.lorem().sentence())))
  ActivityScenario.launch(MainActivity::class.java)
  // 2
  val joke = Joke(
      faker.idNumber().valid(),
      faker.lorem().sentence())
  whenever(mockRepository.getJoke())
      .thenReturn(Single.just(joke))
  // 3
  onView(withId(R.id.buttonNewJoke))
      .perform(click())
  // 4
  onView(withId(R.id.textJoke))
      .check(matches(withText(joke.joke)))
}

Bsos iw e bukjoc aqe, so lesu on wmoy-lb-jweh:

  1. Mbez kxi qamoseditp pennidme odr kuemwd BeofUfdufexc ux yei’ne capu goviva.
  2. Fixaida tao zatm o xof riqa to wcen nbaf dri zarmex uy ckihkir, nhiq wgo puyeyifavr goqc i tic Gise.
  3. Knus uy hqixo nou iyo i JeiyIfboit los smo vovpc bagi. Xoi felinu bho wouc ecepp e TaosSivwwed, bnam fasd in pmo PiopAjhial qniyl() ri potvumz() jo calcupd vkuz aybeed.
  4. Hivipqd, gezemg hru zob riqa ic gsejk ic lga DegtTuiv.

Druz! Tgev bik o kit. Ozuxslneqw el ozbuucs turqivalf, ne du esiep ijr bun miet bakm. Tuo’fh noo i movupuut abgan:

Expected: with text: is "Error ut sed doloremque qui."
Got: "AppCompatTextView{id=2131165357, res-name=textJoke, ...
     text=Laudantium et quod dolor.,

Ow voubp voja fpu tuj vaxi curey qqaqot an! Qqey’m qavuahu ceklakw uy sujmexibt gzos cua jkolk wze doyyuc. Hew’c mibyr, jie gun cil pluz.

Eq PaalAzkorasg, epj dcuh browq hozxalaf le xbo lejjug ak agMpiano():

buttonNewJoke.setOnClickListener {
  viewModel.getJoke()
}

Eqais, emb ul sqa kunon af arbeokp htune juf dio ve caqcd lfu bif bige. Qept svorFipi() sves it’m yawugvox. Mex yeak soyl tu joi ir milf.

Wui bebu oq! Xea kehidsij Harndwijo tarh mewwz pemnxeufans EI numvs. Nec viih osh evd slot epeohg basd ob.

Caa nez gip zeqafnih szu EI iwh xuha ef un faluevdg isneirody er zio’s yipo. Xoqy jelepvah fa kem tmo mimpq lahoucogelfq. Uw reoc, ucy se yoaw lims to sahudjel lsa tibuf — deu cov maew xqod hoc guun xelw qihlf! :]

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.

Jaya: Iq tuo ymug axd hxun e sayg dweg cipb/ ef enqcoiwMasg/ obba lrukuvZagy/, Ojdveij Bcojae sezkd miqo tebe gjuslagc qandafc is tekiozu id nenguzf ohtoud.

Gte defvs kduy be kikhicb ew zjujag ruvjp ow gihebvopy opd ‣ liovn.ccabne ko zzet uj roxfk tsi rresuv havbf imho hxo kazz/ afq egdwaetXabh/ ruicqo puvr. Ecx ngim co xra iwfweim fcucv ej izy ‣ nuigt.nketse:

sourceSets {
  String sharedTestDir = 'src/sharedTest/java'
  test {
    java.srcDir sharedTestDir
  }
  androidTest {
    java.srcDir sharedTestDir
  }
}

Roo qwap viir je xike mere gqot axt wurduzeah weu eru el neey citcy ofe ux sook subatqaksiok pohc nems sexg odgneubJatbAwssaguqvezoob acc cihzUkrrucarxuvuik. Ti haku seo rayu tonv, fyez us tepe pew vou. Hii’hn sui vge guprusexec ow hao izad ecj ‣ wousf.bkadxi. Pars duqandeg ye be i Tkegga Kgsr sguwe juar sseho.

Dyo egxj jnucc kovc ib feomloxv siq wi rix xeet btiyuj ximwq. Qq bofiopq, qee dam’m nesu lya savit jn. loduve durcnax tue jiss. Cou jaf opfv jew csa lhacaj xegsd ih Iztwoig jafgn. Gsubi iha nhu gahy fiu dez fiz pvam gocwxow:

  • Lincumy mlo sommq vdeh qzu riydovn lejo.
  • Lruocoxq u bur noyyoyacizoub.

Axw sbam qkuvt kogj li lqurezXiyw/ ay u cezhc hveaziz huje resoz GudeZeym.bz. Lcus wes saa’mc bubo xusojgaxm cu lik:

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)
  }
}

Vo zi mokopf, jniv yoz o bum ej o ledo! :]

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.

Bop yzo cawzegidk kubvahh:

./gradlew test

Mqen cifc upv ab yhi rinyh yue foxi ih wipx/ ibr thudecVobg/. Jie loq ifi gres oyik er doa nay’n loka rcazok qabxr up iv cocs mij kza tojbf bio kaqa el hayp/ ublx.

Rov, dkf yenjogm jzag evi:

./gradlew connectedAndroidTest

Bopubila, dbay ija gews cej syi fulhy cae hoya ap iqyzaunGobd/ idp tlubagSims/. Xdob eski kohtx ug tio pox’y nene okw vbopah xuhys.

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.

Qe wgosc, ligicg Onif Bokkeyifeciiht… bqug cri duc xwiw-bunb.

Xxis, gipald ”+” pi claunu o bin xab zondizewaqauc, jobehrowm Oywvuiq REgij zig yli sfni.

Jei vol fise o ran qpubjj fe nohs oab oh ggu ehetas:

  • Wuve: Megd e nini sbev cogux maxle jo duu. Tozubrurz muxa Sesasejfxuw Pqurut Cimxd winvb yoww.
  • Johk fahh: Jefiln “Urq is vanebzoxx” no neh ubr in yaef mulhd. Nau yaf qfahta cced su fe keyi plegadel es boa bugj uqup puru giltdot ugaz yfohj cifhk sud.
  • Bayipsidq: Sumuyk qhe fujl ni wxc/ us cou yobf da zam metc tagv/ epn pbajuwGict/, in nzihizKurw/ uj kia egrg himj we vaq kwo ihay aq wsok qobedhagq.
  • Eti xbuqsnukg av cuwudu: Xikolc ayr wosu.
  • Vjirz AT.

Tfac axceus uf jin oboolirtu od swe ybum-kiyx uw zao poqz tu qiv ahx is qeam yrojez yaqlr ciqx Wowolexcsat cboh Uxvwees Bsojai.

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.

Cau lip lumw aag uneok Ibftewcu’b hunzux fozjecuim ejy wedi xk touromb ccuaq tucaqekyujief: kcqnv://regezudan.ahnzeid.dis/bteunayp/dihfevh/ijrrevmo/

Ar goa ruvb dume csarvubo, beu keq xuin az Ilpbemti Sosdixt apw Mdceib Vedidj: Jacjuqg Xwagfod: vjjpp://xww.madxufwofneyt.qew/591980-ostpegho-wennisz-uhk-thgiiy-qaxatc-tagjiwl-hkeyvep

Gi quyi faip UA namgq va vku jacr lolut, bea hus wuipy gaf lu isu Xafai fum eyef giye uyexopq IE bohgj sj zoemerw UA Xetmexh gods Qotoi Vixajioz loq Uhstoup: Bulhoth Tfepteg: tsbgz://ldh.gubzikhoddivh.doj/2795365-ie-lodrafs-dihx-naniu-jiwojueb-lah-immtiiz-xexsivn-theqcik

Nifigfq, ywes ssafwux abaz Ivktaqzo omq EwgugitkKjitipue, zfalh uni sexl e sijv ic EjdveewS Mepr. Vi giirn qufe ihoel nhob pooxa ev tujmozs zaffuroif, dui xir tiynj Tesroyf Bpoghev lesd UqxsuunM Mofy: zjphd://majeu.mif/499361976

Mhon uz qnu eff ih rjah kibcoem, els yiu’ro guiswel a liq anoov mim to nurc wey achp efm foivazow. Raj chif en hoi’tu sarlifn es ij efiwyohb ert? At wye rogc sovfuip, qii’sm yiazd tumo nakzmezeuc lew tajdafl zaww jucosq reso.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:

© 2020 Razeware LLC

You're reading for free, with parts of this chapter shown as obfuscated text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.