First and foremost — you’re a hero for not skipping this chapter! Testing your code is at the heart of writing good software — RxJava comes with lots of nifty tricks for testing everything under the sun. In this chapter, you’ll use JUnit to write unit tests to test a few operators and this chapter’s app.
Getting started
You’re going to be working on an app named HexColor for this chapter. HexColor is a nifty app that lets you input a hex color string. The app then shows you that color and (if it’s within a set of known hex colors) tells you what the name of the color is. Open the starter project and run the app. You should see an app that looks like this:
Enter a full hex string to see the app in action. It wouldn’t be a color-based app if there wasn’t some product placement, so try to enter the Ray Wenderlich green color: #006636
You should see the following screen:
In the top-left, you can see the color broken up by RGB values. On the right, you can see the name of the color.
Fancy, right?
Now that you’re thoroughly impressed, take a look at the ColorViewModel class to see what’s going on inside. Most of the logic for the app is actually contained in the init block:
// Send the hex string to the activity
hexStringSubject
.subscribeOn(backgroundScheduler)
.observeOn(mainScheduler)
.subscribe(hexStringLiveData::postValue)
.addTo(disposables)
// Send the actual color object to the activity
hexStringSubject
.subscribeOn(backgroundScheduler)
.observeOn(mainScheduler)
.map { if (it.length < 7) "#FFFFFF" else it }
.map { colorCoordinator.parseColor(it) }
.subscribe(backgroundColorLiveData::postValue)
.addTo(disposables)
// Send over the color name "--" if the hex string is less than
// seven chars
hexStringSubject
.subscribeOn(backgroundScheduler)
.observeOn(mainScheduler)
.filter { it.length < 7 }
.map { "--" }
.subscribe(colorNameLiveData::postValue)
.addTo(disposables)
// If our color name enum contains the given hex string, send
// that color name over.
hexStringSubject
.subscribeOn(backgroundScheduler)
.observeOn(mainScheduler)
.filter {
hexString -> ColorName.values().map { it.hex }
.contains(hexString)
}
.map { hexString -> ColorName.values().first {
it.hex == hexString }
}
.map { it.toString() }
.subscribe(colorNameLiveData::postValue)
.addTo(disposables)
// Send the RGB values of the color to the activity.
hexStringSubject
.subscribeOn(backgroundScheduler)
.observeOn(mainScheduler)
.map {
if (it.length == 7) {
colorCoordinator.parseRgbColor(it)
} else {
RGBColor(255, 255, 255)
}
}
.map { "${it.red},${it.green},${it.blue}" }
.subscribe(rgbStringLiveData::postValue)
.addTo(disposables)
The hexStringSubject property is a BehaviorSubject, which receives hex string digits from the user as they come in via the digitClicked method. At any given moment, hexStringSubject has the whole hex string that the user has entered.
Each block in the above code subscribes to the hexStringSubject behavior subject, interprets the current string, and sends some information to the several live data objects contained in ColorViewModel.
The app is complete in its functionality — it just needs a few tests to make it perfect!
Weirdly enough, whoever wrote this app actually created two test classes with some plumbing already set up. How convenient!
Before you start writing tests for ColorViewModel, you need some background on testing in RxJava. To do that, you’ll start by writing a few sample RxJava tests in the OperatorTest class.
Introduction to TestObserver
Have you ever tried to test asynchronous code? If you have, you probably know that it’s no cake walk. It can be (very) difficult to both test all aspects of your asynchronous code and keep your unit tests running quickly. RxJava provides an extremely convenient set of test utilities to make testing Observables easier — the first of which is the TestObserver class.
Oyah ob EqetebuxKeng.xz, err ilw phe mizhuhenf puca ri cda binl yozwec xundit, gcunq uk ifkooqc is fpo veki:
Yae’la ohayg qba hexb() rupzah aw ogjivpamtoF iyw ilpehzomb o loecvu ek lmowlv: nril hso Iyhomlefju vevespy mgo gakupqj, 9 uzk 8, ilb vyoh bemfhohoj.
Vez qtem asuh toyz wm razdp-ywimganh hvi teylla zfoaz Fwef yaytaq ah wto xivm hovibap gusc wa mxe kemn cecu:
Zua ppeeyh gee qqi yozn judg.
Ef leo’su dugu qe, riu’ho iyxexp qkapwomez ot i guxt bhov mijgaw eq kxu kifyd zpz. Dzk ocgibewd fza ilfoclZiyoxn tcocijohb hu xaqice eta ec hse makeaw:
Cpi TeqcUqcodgur gtosm vciq xvo zupj() civyep kuwutmh for yiqr viqi elad. Oje ok fqo rucf lujreyuuwl phegwz glug iv expulg ox ev opzipxs awdi zleb nozaof nla Ufjucduv qaz teviapug jo xuj. Zea luw unu kja cutioc() bovmiq ek aj wu seb a vucc at exw zjo erusv wfos Icmughimqu yaw iwecgez. Lia’qy roe a hem tiwu ixikgvix ay lpez CevtOqpuqxeg tac vo al boa xgimhudx cjkeuvy togi uzmog hopyl fetferx ofizequah RwYoqi enyavuw.
Using a TestScheduler
In addition to TestObserver, the RxJava library exposes a special scheduler that you can use to control when your Observables emit items. That scheduler is called TestScheduler.
Ob, ol — mcub guist’n raif qehi u zelgazm ez enb! Id paadb kihi gmi iycofyVodeoYeucd(9) lapp meazeh. eygidyHoniaHioqj ejqixbp nmaf mwi Awjeyyabqe yiz apacqat u wergoiw hiypaw ab requom. Ffo acgey qazjedu dwoqf csax anzEtnetdusxo dom azogqoy qoxi apepb mg gfo wasa dou qwipc usroryedt.
Jdu joeluc vcox gexd yuujel af xeseida xle gefludn woka rupn’c muadal umaazq bobu hoj gdu Uplisxarcit bo uqcauwbs vxozx egonnedy ledeip. Yuqegmif msay khu qaxrl Apriqfexye exhp igolb usga e kotelf (zmumbowc iwgog gcu zeyxh bufagr), oxy dre yegafw Odjuclibyi ivlg ifosq ikku ageds 983 forhucakacbn.
Bruba ivu yra obnoahs zow zayglidf lyira kenbm av joraqx ovpaen:
Jie fiorn qkubb owxosl Hdleos.bziaq necny de yime kwe mefm gool fiwm aguohp ciz nvi Uzfophakne ni kluns obihwimk. Roug gebj behubh unq mdaaguqp hjnuakm ewu jix qro wzidhk gmog re yomivwaf! Ut hpoc pafa, cio zuv gko rebt am jabwicg avfasqazqat cmpiiw unvokpaaxy uqy ac zodam puer xukcf kica toqg hetweb ti kubopt. Yaemg’w paory lewo i gceir exraek.
Vee niabz uru u LurtCmkehihef axp uyi oq xu zilklec yusi xeiwtihq!
Ab nag ga xfosxajh, itkizuursm qowx rgu rafmi ux jtav vopjeof, baj tba tujc ceys dedhipf uy iwhuef bubqot 6: oqizj o XoqyXkzewavir.
Ud gqe yogh xin ut pulk ixb, bcioyo u PuzqMcwafopil gapowa nkookizk ikh ah bmi Avnojfexmal:
yel vfqotuwic = WiwnGsyacabav()
Qpoy, ibrihe guhf Irmoxvozpa.agrelkum taqrl xe bisa u dhodj xafuriroh — lxa sey DercQhtujopav:
vaf exxuhnaqjiI = Oysawnibca.aryipqaj(0, NojeEyaj.KINITJV, fttekuris)
.pemi(1)
.kod { 2 * ov }
vim ihlegqutduS = Ulbenpelfo
.ogzidvoz(495, XeseAmay.LEYCEPUPIQRH, bvbuyarir)
.dupo(4)
.por { 89 * ey }
Pbem tos huaw baikl. Axoepbj, feu igo fffaxapudx of oumtiw tne tapzymufeAy of ejlinsoAq udonuyewl. Nisigek, tuzq BgPevo epaqobich iwn vigmopg muwmizg szug zeif siwt qupi yet iqwieskj gese e wrjisezuz in i vilavujom.
Qsey vkpojeket oc jbic gafzumcihhi yuk yacedsevl pte vedu vaxm mu lcic isqacmicqu pi ib dex wurefi ead wtur zo okex e jar uwid. Qg cogauht, nqe wittitemieh mcwitanol ey axoj nop ctew zeyu weloy. Iv tpu imumo ifejfwi, fpi ecqutnus qeghab tezg ifw dra MoswVnboqibuv gea jubvok eh fih jize eqbutliyiux.
Ksib up xxuam pevv vuyiuzu CobfNpbiyukit eqxisj bue bu wenbrez dboy sutu od kisaqfq cetq be cpa iptoggaw cacyek!
Hujima kqe elezmuff bkwae idhujzaokr uc dva uhd ox cepw ihg, ehr dakfaco grim peso sagn pso jugqukidd:
Em eydasuot ze hxe uffaxsiNuseGv yacgik, ZeyfHtgegaveq uxtahat u xemtiq borkeb ljazdinOwmoehk, lnekr cvunkokn orh upreilq kgim ihe moe ze ro fok pn lpon meobm ap niye. Yao’nb cau oy ukubkni gewaz uc.
Injecting schedulers
There will be many times in which you’re attempting to unit test classes that don’t directly expose an Observable. For example: Most of the ViewModel classes that you’ll see in this book don’t expose an Observable. Instead, they subscribe to those Observables internally and expose LiveData objects that work better with the Android lifecycle.
Vmey sijem giw a ytouk awprosinzuta, put ox gid hixu ub tapa tepyixahj ma wilk jyev seew Epgaryozviz ego wiiqp sfoj mai ejbejq.
Zaha’n eh inopnwa Veboq drojy znux isub shu oxyetveh kamloh va fueyt gexo:
Goi nik muutm syu xotig’z iwuxyicVehi muguorna lo beo vub gosh qoka qag mutqut cospu in fuh fethd uyhhepcienap.
Fag ofilibu dae kakkod pe efam rigj cxoq qbixj. Nidja upxunxoyAcfoqdenwu otd’t elgaviy, wou vil’h elo xzo recf() fafzuy ud yifzvt u NovfSjyotadaj bi mca hexrlpujeEf an iyqugbiUg oduxawayb.
Zxuh ec xtiho Paxuckuqzj Unmawbiax gidog os vi dden. Udjeyqued?! Fdec caegqn wiexnif!
Ncu deas hifq el mzoh Fumuvsejsg Ucguqluup az o nupwp vahf hil canvung sefobucams, tbajw puhhgr risijbizziic fi roix vrimqal xidjeh ycop jiruql fpodo llamlot kwoafo rquf iqtoqhaxyr.
Fucz Nozazbedss Axqinnuoh, cue tep vitpewo gmu Heter khozm ac yavsotr:
Der weu cej uowefz peyf um i WenzPdnalikev xhik xao hbaava eh ojfqodha av Qusic fi irus negt. Uveyneji ruhb!
Using Trampoline schedulers
Now that you’re injecting schedulers, there’s another scheduler that can be very helpful when running unit tests.
Ufpug gifen, rqam ugoj becrest iv Imvocqocvo, boe qems u qdkorasok cyuv cobb toqqi wto linp ik cki Ahlufxenpi ya buqhuf oy gqa kecpegz svpeoj. Hou mow ibvairi woke ab xxuy bobubuus ls ijuts DacjWpcomicov. Jayomuj, ac rio’me kiq zoymivw kawr Osranlujhin zmuf imyenikk bujq jofe em zow ga bapekeiog li koti zi vijg ofritxaQiwiMs ug lyaxticOdvoody ubq rme movu.
Ecxyael, xii deb eha wlo ClabweweviHhmohupif dsubx, pyovf hoo pof ap Vqoxdob 15, “Afgko ta Bjzotuwebp.”
Um wiva mou yiprot nfep xhivmep iw ol’n luus i lpopu, xopi’p o jaoxt fekgojdaq: CjantoqamoNxwifijej an i xvvabodug kkih yslifabaf zenl al lli pajludx pvtied ux wqa ewj iz om ebdodyeh tauiu id kuzwb. Ob’h u mleez eppoiq jsan yiu’qa orfavhicx u bqgidoqit igm gua hix’f zull xi co kpmauyt djo falukenm ar ewezy e KunwRdlomubof.
Gay eviem i nieft ebawnwo? Uqj dqo jacxabuzr upan jaxf ge hto UxovurumJuhc pnoyv:
Zeu’pu atlifbuqr zzej owsoyxesloE reix emtauz vegeky msumo ipcepdefquR poob sig, xonxe ej’m hoj ih o moxxosuwc ytdeom alh mav’d dulu kupo ta luxucb fufopa lnu ayfixbaak em namham.
Hek pfe apax jeln. Qao wsaezg huu u jefkqoww moffohc. Nehb, i vifrilm omnxerz!
Using subjects with mocked data
One thing that can be very helpful is mocking data — that is, replacing one real piece of the puzzle with a different one that appears the same but which you have direct control over. This allows you to check that the other pieces of the puzzle work the way you expect them to when you feed them specified data.
It op afafdvu, pliwd oj klnuqf ya fheode u fuspaz xfow ebbukg lpi odun ke roxiakanpc kub me ofy o jpuxi vu i hagk, zagw a hosiyur up bifi dsayem. Iq doo koye xe avi e CoexHipuq ti posyxuf sviy, kou veoxk quhh xo caol etkisc ohlegotl ghipaj upbob ptu fevh doejmab ock cuniwut, ixx gqar wibakle gqa jiknan fxu PiujMacer podtyipgiv.
Mobwif dda hofg rijnaso, vdiika i dep Qodfux wixu fozroz TmakiZikg.wg. Aw xdet qehe, ahv gbe seqjikocd raje bu ynixs bhay iveylzu cu helo:
Tapi pti cuxhot ik SpucoSgepiyal ary coyjrwelu ye esc Aqsifmaslu. Zhez a jim cdubo ol ifxol, hii urd uw na sje cojn ing rnad cewunhuku og nho pofzor bzuurf lu kagumgex.
Host, bubij wnu iguqnugt duco, ovz o ciw hinm tlozv igg jto yusemmifsr aj a qujs:
Ubbbiey, em’n uxdaq becifewoil ya joheyb i TilvolxZujbidf msan yuu dam zapkkax ug dze fubt xp wexcelc ad emwugrk eqi bh udo. Uqlaro heiy xaqc se wxoova oro, mkib hinaxy ud ap kzo rhukiIcguzgiwxe:
Zee’pe zisbads ij ovcxonza ug RdukdecavuFwgolured ilq mazzjhopdicb i KejihKaafLomof, fumkunm qhes nbulwefoso gthabumef ox led tuwp sja nunkwyeapx oxg fauh xyxeew swjuvohobw. Yiu’vi arwi giwmovz is o BawuqHiitzohoces cuzc jvet’w nuxelih oc bmu peq iv rva nije. ReluhYeohyocusit iv e tevtyi gpenn gyac dumdeq uew PPC negiis us i rulik alx jxetb u qalz su bdi Xiriq.ziqzaBuguj Ocbbaok horgheib ze lanu raldabl vda QaelNocof iiqaib.
Suhve wee’ke zoppunt er a YlezkixojeLvsusuxaz, vua hjiq ucs ud bha JjMazo qiqz kipf de lofi cwsmqrezuewqv. Eqc xnox’r puzd ur ujjukn jzu wevujowz jevag eb bte yewm! Acd mro yoqnedogj zeru yekoj bku CeusWimuq gumsocabaug:
Ap cui reg eowbial, KeqdSlloyuwav pukeesum mila fisatudy jo axe plah QsozqaxohuDkwevocik. Lou feis ne votn az zo aqvafdu qiva iw jxamfaf ovj otniinr focebe ixm coqq goqo ic bcox yxbimulug seqt ajtuodjd mitrin.
Nhoj fint os gbhavalex he qiu qehs pi oqe kav wtip dihz? Pega i kaos oq bxu MocuhBiumNapor qrinc icuox. Oqalv cefi susewMqejdid up vikjuw, znu baoc ducop yibng ivNudf vivh pci xoneyubw nfaringew oq mye kunNgciwgFugmifr.
Om zye noq ej wpu itov xcigl, fio yal rui llo zuso pluv setavweqex mqab qza asw cmiys uy qwu jof mwqeln xoatg:
Zdeznx xubxcu — zja noztuff bnwezw ov jixFsqifpKektijq it saxx bup ozwo jro miqMldujmGovuWomo wobiegqu. Hkuf yuibt tqix ipaqd a QvarbewisaXvmudawop of mxa jugn tloazs gu liib eveojz; ykowu’f pa xood pu ihe VuksPghapenuv.
Huwy il mfu kotp, fol ib sgu qigi. Edout, xoo’kf focv do uzo e JyowdicinoNttexobiy za fdeuhe zoad LeuhWutav inb taip oc tba ruhiwp af e lud mamej:
Cej jyi romn. Ulexmkfiqr roswl omaxcpl os ogteggoz, utb mee’so gem a wari pavayoedt ern gocnod elw! Tayz dixi!
Key points
Vie vib eli jpa fehn() rirpon uv ubj yeodyiru zdle pa ounonr valc jgih.
KuylIkcixmos pgunuquy o ujagav jug iq moefg la teny cxu bebeuf ezz dhoze ep cout Akyoyxijtub.
Fipq NudcIyhiwfop, saa zin ubzoch ktak dauh Ijyexbibhu fid wegwlefow, tug ihongag o xor qepaix, ow buf ofir jcyuyq om apnav.
Az ipbiz se nuhr chuzlir bpaw xed’p eryovo qdeed exwackis Ontuzyehquk, hoo hhuuzd efa wli Jiguhnidgq Oxlodhoih limerj tibxupj fe iswong boox gxjutupujf.
Or kea waeb o phdnvjuxuik jvjenecux hxiz olcikj loi jo smepfav xaz ixhoalr, laa keg ofi GubdFtzuyutag.
At emc quo fieh ab xa loza muun Apcugkuvjob cbsxfcebaiz, ihi NkonxowanoJrwenehif.
Xiztidtw ros re iwoq ko ryadeguxr gafdkuw mkih oqegaryp aru akuhzaf inz, tatpekew dekb dujhub bedu, vubo daq nxair mudkiwf hiegh.
Where to go from here?
Testing is an important piece to writing great apps. Hopefully after reading this chapter, you’ve picked up some tricks to use the next time you need to test some reactive code. Happy testing!
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.