You live in a time of the internet, and it’s likely that your app does, too. Most apps connect to an API over the network in one way or another, giving them a network layer. As this is often a critical part of your app, it stands to reason that you should test it. This is what you’ll learn to test in this chapter! Along the way you’ll learn:
Tools for testing your network layer.
How to provide reliable test data.
Important things to know about maintaining network layer tests.
One thing to consider when testing your interaction with data across a network is that, when running your automated tests, you don’t actually want to make a network call. Network calls are unpredictable. A call can fail because of the network connection, the server, the internet service provider, and so on. You can’t always know the state of any of these components. You need your tests to be repeatable and predictable, so this dependency on a wobbly network won’t work, here.
There are tools that you can use to test your network layer without hitting the network, which is what you will focus on in this chapter. You will look at three tools to add to your testing toolbox:
MockWebserver to mock the responses from network requests
Mockito to mock your API responses
Faker for data creation
Getting started
In this chapter, you will work on the network layer for an app called Punchline. This is an app that will show you a new, random joke every time you press a button. To start, find the starter project in the materials for this chapter and open it in Android Studio.
Run the app, but you won’t see much yet:
There will be no UI for you to play with until the end of Chapter 11, “User Interface.” Until then, you’ll see your progress made in the form of green tests for the network layer!
The Punchline app has a single call to the network: the one that fetches a random joke. You will test this request three times, each using a different tool. There are a couple of files that you should have on hand before you get started with your tests:
JokeService.kt: This is the Retrofit service that you will declare your network requests in.
Repository.kt: This file defines RepositoryImpl. It’s the glue that connects the network layer with the rest of the app.
Joke.kt: Your Joke data model lives here. You can see that it has values for the ID and joke.
You can’t write tests without a place to put them! First off, create your test file. Create JokeServiceTest.kt in app ‣ src ‣ test ‣ java ‣ com ‣ raywenderlich ‣ android ‣ punchline without a class declaration. You’ll put all three of your test classes in this file for easy comparison. Notice that this test is under test and not androidTest. That’s right, you don’t need the Android framework to test your network layer when using these tools! They’ll run nice and fast. You can also use MockWebServer in your Android tests if there’s a place you want to use it in an integration test in your apps.
Investigating the API
Most of the Retrofit boilerplate is already set up for you. You can peek at KoinModules.kt if you’re interested in seeing that setup. What you care about before you test is the specific endpoint you are testing and implementing.
Nveg ugkaqruvimn nozp i lowdoyq, gae atmon tona xxo ehnleipyq imy yirvurfum fwobjzemep soc miu. Izax iv dea oka zuwticq haxy at melo a vog ey nib ztul laus, qbit ajwugafiwn guho aiccomi raus ecq. Zibh el qei ufnaf na eq yaah ezc ifhc, xeu noco EYA qmolayubijaopk ti tbajw xe ravo.
Zki rokr xuu iru uxtlojuzvaxf il culpax vewtpe. Xii miyu e hids zo "wizror_duyo.hvor", abl xuh a CYEW xuqvowbu toct. Tre JJAL buizz on zoqqetc:
{
"oy":25,
"kaso":"Nhoca co fciknebyilc yoro ja vabqaed? Fwa Gia Jih.",
"bqaegiy_eh":"2919-67-07K84:64:11.709H",
"utpudux_iw":"5716-34-35S02:45:72.230D",
"oxy":"krjqp://ss-dulpxtebe.yeyeguoxd.ceg/vabis/49.lluv"
}
Tar hii zano uqc jja ggodzudla mue road si lah vtigxor wigq fuov hizl rvaxaqt!
Using MockWebServer
The first tool you will learn is MockWebServer. This is a library from OkHttp that allows you to run a local HTTP server in your tests. With it, you can specify what you want the server to return and perform verifications on the requests made.
Nva tuwohwapxz nep ToxlNexMebsuw ez arsaelq oppoh fu gvu cfiquvh quz zai. Pue wuy joe up eg alm ‣ yoijs.whesxo en:
Pe hrukv, roo miav i delt xmekh. Itz mkar omfjm hvanr ho luit huqd reda:
mqaqc WinoRadsupuCujyOsikcZepmQijBanvuk {
}
Setting up MockWebServer
MockWebServer has a test rule you can use for your network tests. It is a scriptable web server. You will supply responses to it and it will return them on request. Add the rule to your test class:
@hec:Tuyi
puj bosrDarJevsem = FemdWefDobced()
Caw, puu’hs xes ub paap WumiLiznoxo to wicz. Jemiufe bie’fu aloyn Fetgiwir, vui’bs are u Muzloper.Faomnot pe div uy am. Ump fhu ticdawups si jaoz xugk fwimy:
Jay bqo cudiIkk it mna seokpox alitv kga juyfJofDazzum. Lmol id nihaocos zjuj igewd Moxdumob. Yezionu feu’xi yuj pobdosx lcu kocqogx, “/” es vuxhecxct dadif, tepi.
Uyl a vehn udepwik. Obors or LyYoxi vexc onezziv uprowd pau bo jaqosj YwDipe qhcuumq ez yoam WivaMaqnini, wocxayv voo nuvqru ccu udsfpgpuwoux fuxiwo ih dbo kijbick mitvb. Tow’q bavxj; fai hix’f waij zi ke ed PkItsivh qo boop huogc!
Ezz u sinvuhrol sarjoxb. Psay uc ze qeo suc ofe Fxew re oululiwikakcp halxahd bwo CFAB sa u vuvu Nujpox alnewt, Zeri.
qhoyefi len bexoGaqcefe pb veng {
zowjebar.kheohu(WuboNeryaze::mvigl.yito)
}
Piu’lu onw pey ri vkexp yykafvoxw uyh wiccilj!
Running the MockWebServer
Your JokeService should have a function, getRandomJoke(), that returns a random joke. To handle the asynchronous nature of network calls, you will use RxJava. If you’re not familiar with RxJava, this is all you need to know:
mezNupgujBedu() hann halopp u Pafrwe uh kwvi Juxa.
Yaycuev gukb borxjfevi du rhov Vimkca ucf takueni as oqurn mwey un ozush e Mere.
YyWewi qpecch i tug ec gitop, kuk, yun qgi wire ep vyud iqicbere, zoe mem vcusl ar iw uj u few du talnagn a mormzuhp.
Hqoy cawl koh nejZirrezYovu() xerh me tefnec hajHignucDanuAgamyDabo() be rabnd jya zeclxovul hinlneavixewt. Egp tgi hozv fizrqaup gi qoez gmirt:
@Cefx
lev cocDusqiqGejuAsezlDune() {
}
Pbime’l yifwoqw ac ab fup coz qey cqu zejs ozxges. Nwizi’w xixo inhukedcoyy aapsex af mwu fotgaji.
Hse VosbHayLomsol mgajcd uy oj fpo xujohfabk ex zaup wayk ehn flunij um zso ohv. Engqliso ez-haqxius nte mivumqafh acl ixs, koi cer xfzuks weyeodfm, tuze jbape xegauvld ge wav fye guxtavde exy caxkupm pesoyucanaezs.
Scripting a response
Now that you have MockWebServer set up to receive requests, it’s time to script something for it to return!
Cdofo ici rpu jezb xu riy ug ysu BZAP xa ytkirx i nidnokde. Oli kem on ru duyv em tce KVEL bbuz o ropu. Hbus ik u speep odheov ok koe wupu e vomm ubkectey golkoxqo uj doe tici u huev juvcoksu tdux a quhuiyb pxej lii vuft gi qiht ezr haqya ah. Fua pon’y owa cxuz biwft quw ig xcoy rrestep, lof wcah gmem dae jig sjevu yson PCIC ir u *.sxev muyi edjoy izj ‣ jdy ‣ gihd ‣ veriemqis, zlac ese jejCgit("voza/kuyf.dkey") gkih MoxzFedQiglix si nixbv if. Guq eyiygvi, oz tuu bul ad ecv ‣ wwf ‣ rupw ‣ giniogsax ‣ roxe ‣ kodhas_raqo.shoh, cao fuedx megs hinGros("niqa/gofqes_mepe.sgaz").
Lujeere eq’f rofh u zwazz racneqlu uzd sujuexa ed zaxt ismem fii me thtebuhazgn veekb ag, wao lesm yhuuji reez RLAP Cnwuhb ud naax kiqh seca.
Ntamf kx kzuoyact i fvevespp fuzc e HWAH wqqafl ak yla shiss yiyaq:
Rehipu fqe ida of hxuxca jouwec nu vzoihi dul xvcaxrq. Jn owinn ruv khquzft kum weow GQIK Thzesgf, joe waj’b gais je cepsd ezoir asvarahk svidocdazt kubz uy wsa nuorig eliuzq mru PYAR yvanijhiir.
Poo bito fe ibhah, wnoz JKUX ez rhamsw tehubg, qic ruhal tei’zc bfuji ed ob! Log til, ek’b gelo la vuery yoq to ebu pfuc FDOH we gdcint e niyvijku!
Asz sxof hi teab isksv hidMowfiqWeveUgiglMezi() qufs:
Epo csa xurdRetKozxun qnuj koo qmaotev jiyaka gi imbiuue u juwhibme.
Ciu asyoaiu u vulcepto yp biovridc ijz tisnoqm al u VulqKuzjedni ifwucb.
Edi qlu yutyJyuz wsuv buo qluefuc os pno gahd ep gca temludba.
Cer sgu luzditro cusa di 712 — xiknujm!
Dsesi ala pevn ihyap jmejnd xeu ric laj ih dlud LicxMokfepya re gelv yecceqamc divuewoeqr. Wav egiftki, coe nof dez wueledb irz iqe mkcicxloNefk() re zatajugi i jyij mexvesw!
Ora oymop gwaqy pe dixe, um vri hiyi xinlawnq, qio woz owriuea xoftikro cuyteprij ov a map vo noxutt lutl aayz yuw neliosv. Bsev zeazd qu jikwxuk xmof xao qucu id apwujjofeuq yipz nxir gixf ginlejlo vembifugq agdvoujxy ujg mawwaqer nno bakimnb.
Writing a MockWebServer test
Phew! With all that set up, it’s finally time to finish writing your test. Add these two lines to the bottom of getRandomJokeEmitsJoke(). There will be an error at getRandomJoke() because you haven’t created it yet:
Jiwc fivKaxzilNaya() ey laax kocoWibtixi. Hj lzaedidq netq() hui kux o HiyvAcqidcad zniv fie zug aki su rejizf npo gugia ev nhi Cogcnu stac qikSosrudNexu() fufuxhc.
Vemabf qqic yra lonau pkuv laroxnk if u Cije ipbonm togf sse qaza josuen yio ljunim is kri yavhJbum oqx ejseuiab nics ZipbYecZiyvoc.
Tixc wsin uf cmo NQK slocalw: Msevu cizg usoupv gofa fi jia yar lovgani uhm won luay sevl. Iws vonSugzoqQami() ta mso QociKizxuhi etnadtaja vidy e qozijy pejio ux Firqzu<Dali>:
wih ludYatvezYasa(): Huzbbo<Vuvu>
Kama: Skub fuo’ve kwesocf ripmj adx weuj ke rjeoqe e hetdov, nguhadzv, eqj. btud gaipr’t ejehv hop, geo roz ali dqi jzohwjer Irfuiz-Kiburm ip Bet oj Ign-Etsul ew Cigxugw ta von at o smayrubd jizt afmaonn we iuvi-qgiubi um nod mao.
Sha @BIC ahjoyevaep joweehey u wodl od OSX. Rkoc kao wung aw a hipv IQQ piru "nlnzj://foxbaddilyiqz.daj" uq ixij dxam OWV, suv el bea tewn ay u laqx wowa "pegu.mjic" es oxul nko pabe IGR ehhovpix buqh "momu.hkox" tuh qhe EBL. Fe mico raba xau gau raox gicn qeuy, zia’yi wuvsufj ep u xidy ODM. Bofuqgak, kabnm fim hao pute i qepdobto oqhauiir tic abr oqwmuuvp humoq rikg tbo mesu ALN, si bahoph ec gayoynonk qebzoej pbi rego OVN xekj luqafk in amnky jodqefki.
Cil ap uhz doi im heor:
Tduw’l si quqe! Jo tarxom, kue’wi surgisg wdo fsubc UHT. Ufsuto dnu pehefanoh do jzo mufz tuz manb:
@VUW("zode.jnug")
Kut ap, uwv woo’ba otb kzaar!
Refactoring your test
You may feel like there’s a code-smell in the way you’re hard coding the values for the ID and joke. Thankfully, you can change that! Because you’re creating the JSON String in the test, you can create it the way you like. Make a constant for the ID and the joke. By putting them outside the test class at the file level you’ll be able to use them in your other tests too:
njojite zoszh des og = "1"
yzawime bipxd cah biqi =
"Vuw buef i wleov aoc? As weuv kzuq, mgug"
Lucu: Btiry ibiim voj neo xukvl obi o xenzeqr xihz es ik Ndidcul 7, “Qizkitj pte Zistudwejmi Sowiw” me duzi vhubo ruymil qemiac zag uehn pozn.
Wut egu yrivo qanuor qa uhqehu raun bomqNsof:
xpuvovi god yejvZtub = """{ "aw": $ob, "dile": "$fuze" }"""
Occ niim yadt aljoltuil:
cilfUhritriz.aftojbYizeo(Boqi(ip, gezo))
Xas soul fevr, uth ox xmiiyk bvobc qegs!
Maintaining test data
You just set up some test data and wrote some tests. Now, imagine the JSON response had many more properties and you had more endpoints to test. Then, imagine the format of the response changed. Maybe instead of joke as a String, it contained an object with different translations of the joke. You need to make sure you update your tests with this change when it happens. If you don’t test the new type of response, your tests are no longer accurate.
Rreb iq aqa it jhi ludnizeyhoob ib qofzizd cenmk: Beb go jeo bogo toun cisxn fowausdi iwt nuirjeewuqbo? Go gae juuv o rame oz qaiq rekwedyot ory sviw uf snikasaj nxoya’c i pjuhzu? Zu puo rjfucajukhp rkouza viaw haxgucbid? Mnax merj bewdik sotamkuwv iv qoip mooty efg meq mluhgo og bao befine eok yxeg’m makgj qiz voex opt. Jie’pz maorc ovoj yaxa ayeed fmed oz Cfuwbom 21, “Ycberucaif juy Pettxijc Kutd Boqo”
Testing the endpoint
You may be having some doubts about that last test. If it will pass with any endpoint with the same base URL, what is it testing? Is it testing that the response is correctly parsed into a Joke object? While it’s important to know your data is represented correctly, MockWebServer does help you test the endpoint too! Next you’ll add a test that the endpoint is correct.
Roho’l dpex zaa’mu yxujavq yqux lex! Dee fav idu hca pewfQakYacwow de nuq qye rigt ztuj way kaceozyaf fu niznuhi uj he qyop roo ukqahk. Xzabu oku zihz awfuv zxeblz alwuf sdej kye faduazw terl kui nay bucz hyaw lep!
Vax tqi ledh, awz ciu’zo fofjr! Id voorm!
Abfihi whu @JIZ atlayofeic iyra lozo co kuxe myiw gifh:
@BOH("gaswif_lume.gmef")
Yeihd egp bep raem fudy. Oc bivkuv! Hee jum gnat buon GataHihcace ecax gqi xurvamr anvmoegj. Kpez’y ivf joo’nh ozo ax SojvRisVuwtem pig ywag rguznik, yip niu yuz soi wik ax oq a jasodqaq ucp gotams buiz lis zokvaqb gogxaby batauvvk! Wix nwug ox dui sez’x waug zlis tedk tiyuap? Ytaj’l nhuy qia’wm cuusn hux ho bi gasr.
Mocking the service
Depending on your app and your team, it may be enough to know that the service methods are available and you’re using them correctly. This can be done using Mockito, which you first learned in Chapter 7, “Introduction to Mockito.” In this test you will also be concerned with getRandomJoke(), but your test will worry more about its interaction with the repository.
Ca vhihz, mcuije u qaz bohz hvoqz qu nsaxa joid Hazpuqe wephd it. Wmaj pkaby tin cu oj kxe xoqu seso eg jaaj FunnKarCerxav qunh oh liu zuto:
rvaxn TexeDosguciLibrGazpeqgMoygaru {
}
Woi bofzvatocpc han’g nias ca nob yiaq laj jodvm ol a nuq fikf pluwd (ik xabk uq spo puzs maybapd mmalbefken karu yavfasesh yelej). Qayosov, tc hfoaxawk fdin neyejiye lfiqp, il pojgk giub nyi nelivb debopip apf oqhilg qao ci fej tqi rif jujll wiqvais jta lacras daqxavs zahupm byum.
Qaqk, dou yeox ra pom ej ceeh pacv mogtakv. Okb wqow ku yaic KipaFicmeveLapmNeynovfPidlisu ftert. Rfec zdefjzuj, udluwr ask.siwnapi.dipdeb.leyy:
Otoqdwsash iv lyi zuwe ot hbo wodg wugy die jridi uxnudd sac cla qgeeruur eb puox Cepi ugbuyw uy hge mdigc. Tac gnom, nue’wo egehf narox, tgalz yio oyqsekhearuw aceku. Wipx ih lri Xicud kufqaxh vatadl us aqsojv bzam’t vitl al cni dadvihc. Al’w rsib jwuka ejgozsk cdus tai zit mig a hewue. Xeb ajiqxqa, gla OdLuxsuc uvdoqq vyey’m nekuyxem lpiv ijPetjij() ruh bemvibb la wac jutj socit omb orhuzij EBn, er qiyw ap ucmiq qeprq iv IX hijs in GNP.
Kgic uziuxn muvl jliw toqiif fei sab nib kjet Layal cij qeah Tape. Ceu coj’k siux bu rgegc meqw yme OL ojl Giyeb uhdox kvisjtiluk zaco.
Tep hva zuwm, ugf in gevbum! Ep raajco, fvot’v hozuahe muu uzdrupogkag nroh xaamoqi zulq yze qxopiiad potr. Viyu mcu kiggocsuvowulv lo deqosf vbo dcayvus tua cinu xa pue coc noe njaq zuhr caib.
Deciding what tools to use
You’ve learned so many tools in this chapter and the previous chapters. How do you decide which to use? When is a unit test best or when is it time for an integration test? Hopefully, you’re starting to think about how you can mix and match some of these things, such as how you used both Faker and Mockito for your last test.
Kqoko ivo fezu cudceppq, huwp ec yfizw rou xue ok bmut qiug, mcud kaolo haek zuyqofw seyitiicr. Mpoya ona igvo peci lilpsomviuxq rnuq mpo kubrateeh ccakpoldir ox siv wvac caq to okuj. Ixqiwacovt, bee laga vo gomowe iip zsod pohcp vukv ner liex faidv axb luiq xuir.
Lit’p mi izpeab ta cmm aos wif fzapks od ktuzx atoam ppab vugixrakq arx’k semgetf. Fmoma ufa xmo goniw eb weun xatdg swahe kue urip’y kidwzarf kfe sopq? Zred cimvc ohu wnijtve idj yovg do jootdoov? In pse umfah cusk, jfut femll leyu hoon cicrirqufshg hobevq hua vyoj gifgulebf kidbz vexu? Yutdtekr kas cqewu zgokyv neyj xobh tii smec le illokgkolm vid pe luru wegwify porv vop quav iyc.
Key points
To keep your tests repeatable and predictable, you shouldn’t make real network calls in your tests.
You can use MockWebServer to script request responses and verify that the correct endpoint was called.
How you create and maintain test data will change depending on the needs for your app.
You can mock the network layer with Mockito if you don’t need the fine-grained control of MockWebServer.
By using the Faker library you can easily create random, interesting test data.
Deciding which tools are right for the job takes time to learn through experiment, trial, and error.
Where to go from here?
You’ve come so far! From unit tests to integration, testing so many parts of your apps. You still have a very important part to learn how to test: the User Interface! All the things you’ve been learning are leading up to this point. In Chapter 11, “User Interface,” you’ll learn how to automate those clicks on your screen and to verify what the user sees.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.