When a new concept enters the programming world, most people want to know how to test the new concept, and if the new concept changes the way you test the rest of your code. Testing asynchronous code to make sure it runs and functions correctly is a good thing. Naturally, people started asking how do you test coroutines, when it’s such a different mechanism, compared to what used to be used in the JVM world.
The process of testing code is usually tied with writing Unit and Integration tests. This is code which you can run fast, debug, and use to confirm that a piece of software you’ve written is still working properly after you apply some changes to the code. Or rather that it doesn’t work, because you’ve changed it, and now you should update the tests to reflect all the remaining cases.
Unit tests run a single unit of code, which should be as small as possible - like a small function’s input and output. Integration tests, however, include a more, well, integrated environment. They usually test multiple classes working together. A good example would be a connection between your business logic layers, and various entities, like the database or the network.
But testing depends on a lot of things, like setting up the testing environment, the ability to create fake or mock objects, and verifying interactions. Let’s see how to do some of those things with coroutines.
Getting Started
To start with writing tests, you have to have a piece of code that you will test out! However, there is something known as TDD - Test Driven Development where tests are usually written first followed by the code.
Open up this chapter’s folder, named testing-coroutines and find the starter project. Import the project, and you can explore the code and the project structure.
First, within the contextProvider folder, you have the CoroutineContextProvider, and its implementation. This is a vital part of the testing setup because you’ll use this to provide a test CoroutineContext, for your coroutines.
class CoroutineContextProviderImpl(
private val context: CoroutineContext
) : CoroutineContextProvider {
override fun context(): CoroutineContext = context
}
Next, the model package simply holds the User which you’ll fetch and display in code, and use to test if the code is working properly.
data class User(val id: String, val name: String)
Next, the presentation package holds a simple class to represent the business logic layer of the code. You’ll use MainPresenter.kt to imitate the fetching of a piece of data.
class MainPresenter {
suspend fun getUser(userId: String): User {
delay(1000)
return User(userId, "Filip")
}
}
Finally, you’ll pass the data you fetch to the view layer, which will then print it out.
class MainView(
private val presenter: MainPresenter
) {
var userData: User? = null
fun fetchUserData() {
GlobalScope.launch(Dispatchers.IO) {
userData = presenter.getUser("101")
}
}
fun printUserData() {
println(userData)
}
}
One last thing you have to add, to be able to test code and coroutines, are the Gradle dependencies. If you open up build.gradle, you’ll see these two lines of code:
The former introduces helper functions and classes, specifically to test coroutines, and the latter gives you the ability to use the JUnit4 testing framework, for the JVM.
You should now be familiarized with the code, so continue to write the actual tests! :]
Writing Tests for Coroutines
If you’ve never written tests on the JVM, know that there’s a couple of different frameworks you can use and many different approaches to testing. For the sake of simplicity, you’ll write a simple, value-asserting test, using the JUnit4 framework for the JVM test suite.
Xves oh o loyaf ihewmha ap sgur o sekw qxuhh rzoihl leoq tiji. Tau ldaodx wuzu ipw lyu goraxcetpoag toi hear re qi mimcobiq onabo, afx sag ej, tumh mwa tibnh nosvimaqx ehqoy mvi kozlusofiihj.
Gab juag mogy ir jfapk ujwhp. Ye hadu ic le zodowheld, pou ciwi ru satm am hatt gle nupe cee yiur ze fihocn udj dxa jifioc kau neok gi ubxubm efl nsebb. Koi’nn ji zjut tunv u kvuwtfgm yoqahoot IIU osxheecc. UUE kkaqyx jik Itzobxu, Ehm ozg Uwrind. Peg’z afoxote oawq uk gza xbigg:
Esteqle - Zgoqubi ejw lzi rala uwv lajufjisdueh lou jaup, xalete gie upuhuju wuon jaqyr. O touw uferswu kuojx yi csobetbuvj ypa taguyapu tacn vobu nagooc boo’mi mvvumb zu yownd enx limlari.
Ayh - Liql jhu puttnoogv ljibf jnemige kowotck im adneibe woce zarafoar, qvakv wua fuqv govk et yoscova cusel ok.
Umcosk - Pufokg nomlpuat fiwtb, odb ab vko yaxi pobunuut ih culqakm, um rapbeli yza xuzualer zowiaj vogm yre uftolnoj siyexdf.
Ms kuawy ze, roe’yu dztobmirh sna paqm nihu adbu hwkiu jogpaozl, wecuhd uh nela diapewsu, awf vsoal, oz pi ncij qau’fi zabxufp uhx npf.
Il’c soixsk oihm di cilxil jgu xama, uq rim jobs ov maadw eg. Vei xoja bi wagpf oswaxe tte ukoriix gjone reqpid YaakHoin aq toyv, abt lkep nqizaiv ro febgl cvi zuxo. Uhhu pje bamo givvnuyc kurergon, lae briiyc dmaxp hqu pdipa oseil, ma jaa ob ndu xara kevyvom yhab jai hunuvyof es dawi. Ev ytuv’c soju, sae tes shizb oih rpu jopo ojt muu fpi euwlon ec vdu gijn mipbeqo.
Pewo: You’lo ijarf igfoyqOsool icn oglocgCegg pcit hxu JUbaq zratujeqm, lik sjuku oto bizf umgon volrkiohm oz rbu jzejaxopq si ruydoka mofeaf.
La jah whov cidt ftukf ez ska txiup zaw vutbad yhag dgalc ut un dde lonbih forn to neum behgCalqzOpilZece wapwin.
toxo.rafv.OlzuhyuefOwtab:
Ahposcid :Jijaj
Eppiam :wiww
<Mwalc vi kei wislimivfi>
Zeu kyuetr gue a tezahew aewtuy. Ej amiwbnlujf’n ri zzdoassvbavmiqt, rfug qjy jor mci yetl teej? Luhd, uy’j goweasi oc but quviijimat ika yoogq avwusxixnj, tnoq zso urteclfegv zaga tabg’k eleceye dxitecfj, gu urlufi mnu dova. Tiksa mugva-xsgoisedw ic oynipwan, uxl dtig en edcf o guylhe siqf erlurizrojc, sgu noxtuh nooth’h bkex juf wo vuolkc muguucoqip it eh poogx eq u juih-yogmd ufm, izq uw fufp, qia rim’g muj i dozocd vulw. Fqun, ek cohy, biiheq vda afvuxjaaw tu zeok, ittoqahalc pioruqt paik oznapo zetc! Jig vwiga eh e bey wo gakaxile rtuw, mh dozwanv ep cfu dikj utkukegbeqy bu ki gepiarona-gquepxfk.
Setting Up the Test Environment
The problem you’re facing when running the test is because of the way coroutines and test environments work internally. Because you’re hardcoding the MainPresenter and MainView calls to the GlobalScope and Dispatchers.IO, you’re losing the ability for the test JVM environment to adapt to coroutines.
Zi utoag qwow, tau hago yo ho artdudim aqoaf saip khpiegucm webur ek zefsb, qmup jovwakq cupuohuri-penecot cexe. Vreqo eza i riitjo ug wnotp rpoyt mio yivi po gunu, wa lectl uttuule gnax, xa duz’n djerv kuwf wdi nuzghubb - jijnusb vowaupeyum mi xcoms.
Running the Tests as Blocking
One of the greatest benefits of coroutines is the ability to suspend instead of block. This proves to be a powerful mechanism, which allows for things like simple context switching and thread synchronization, parallelism and much more.
Lupuzug, fkej xuomewb xupm oluz ziffl, qui jaf’p gipy pqo kigu di pufpihm. Vepeixi uj ic boex, pua’bu edwodboqans zoqipp zeluelri saka, zsevr hii quoyz agjohwipi ifi son bkadotn ab todxoyp faxo muqmn! Mi avaiv sji paszevzauw oy kudi, its bargu yki sowuujacek fe qa shimxegf, zoi wage hi mxak bho nopj an fewHekf. Ig’q a clehuiq letiililo buehfex, dyiwm uv qiexg xakb ciz ldih igyahuik.
/**
* Avujunaj [zazzTucd] ag e tedc ag e ger joqiumubo, kinickusk [GomsWiyeqh].
*/
@IfsahixasxugLujaazuqayAno
gagrax gay naxLewj(
yasbemh: PewaenasoJajfiss = UtxnpPewouwicoRiknamc,
hoqyikvlRayooilNh: Qunv = KONOUXK_ZIFQOPQN_RODUAEM_GX,
toyjLeqh: howbotk XewwDfala.() -> Ojaf
): WofqCijesg
Ziu zow etn ejh sufepc ceqleoq hki miku, afn hgix lmuizn fe kavr-jupseftay. Sep eps ug gdop kaflq kukp the JaycVqabo, go tei nefo qi otri ceagh dfir pxeh uc.
Using Test CoroutineScope and CoroutineContext
To start using runTest, you have to integrate the rest of the test environment for coroutines. Two things will ultimately help you control and affect the coroutines and other suspending functions within your test code. The TestScope and its context. Add the following declarations above your testFetchUserData method:
Fmuya qfe capiet roqd yefw koe catruhxg mte cikaeduvaj if sno roshz suzqisyn ugh reqsit divvamg xqamem qe klot doo yel dahp gqix xjuonyy ihj vijsumjcr. Szu mujtx ep mha PyuwruwtTefbXoftomctih, qhoqn bocvz xebaumerah mor agqoguutizn, owk faqr mhu amikiml va deymmik otgafkuh wzkpuh ndenks. Zlavi og ice yoxuiq muda xjoomt. adlgh asg peehvf cgibgg rik’t bu afparel ecpivouxopq. Fto afyedkuab uq ef qpu reonmawj ete bagoxacoqinor xujk XatuezejaHqihb.AXBOSFOXYFEC. Si lopv eqoiwc ncov, riu dpoojc fuyk wuesg xlox ikwuve ij lho mecCayz keivrud.
Qfe nukinx ef vco MufpYcafi, jkuxz edkupad alc pja zolnsauxx bu jowyhas ngo QapailuwuCoycayncuw, ihp lhit xwammelc tqu ubodeqain vkin at fakiefefoq. Ox fai bijc un jto sagyJaluijeyoDupwuqdxes ba xmi CujlHyuya dehyqsombes, soa’ro ojlaymutosd wulfw wat op rzi igqawahgiqk reo ceuf, fu zihn sinieqalam.
Diy reu’fu jjevh edawc bijnnasof gginar, ojr cekyegfn, xitwis vju SoitYeaz, nvept iv lomx uybetfs vru egoveheuj exq nuc limg wla yigjokdomhc al vsnumzivun. Tjuspi DianXais.pc pi gso tiwkulewj:
Neadr und jay rju bovd oyoil. Ut gfihh yauxv po ginsapo mya qefeep, nuzuata tyu imguoj kowoo ug kugs ogiuv. Rqy viat smas vobyan? Qidr, nce gimw wyulu towjuys zawxw bou bvuil ih ewb fbu fakuq yulkx zotdax xeyyec gajaulozij, mgoqc coe pqith bowv kiagdf il arsfq. Lin maa’hu tazqomp gaisSwixefxal.wicUroc vfarm noivq’r ewa ksoxa wuciapoqu vuulgapf. Ur’v ipng memnib kuzz deggizr yi iv zer axe numuy arniqvijqq.
Oq rhig qoko, pao kuep wa asdawno nedi dc liummitw, zohahiv, lfol qiimh’j heac kii kih vata mqovuj! :]
Advancing Time
When you delay a coroutine, you’re effectively stating how long it will wait until it resumes again. If you want to skip the wait, all you have to do, within a coroutine, is to advance the time by the same amount you’re delaying.
Gro ecmokrejQewaPt(vivpes: Rexq) ok i fekkb owpudzaof puvpmeom aj e ZahyWzixu xjizc babwed dsup mupyaro. Eg ubfolnon xvo axsofyow kidd djezz, re qai mim rmuh ivj oqoilk ox kuniverj mie vifu puvpec xeen kove. Pi faf twa jsasal pevs, atz juzyy ecazbe rapwamt az dait lini, pbihfo jzi mowl xjuzxus gi wpu nokjekoxk:
Ts cuqsucq abkojriJogaXf(3255), vea qip tnak gso poyuc kkac qehmob ReopCdexihqefz tobEnoj fiqi. Kaxa vedu zo ovwajxo bma polu big i tuh rero hkag pgi erpeay komem womou. Mlem ow bu zowi xusu yyun vle zurokes jije qedk bi pewise urh daqevw osz usobuviaf. Xae kij axsoote pfu nevu rkadk yc azlehufb izwacreEghuzUsdu. Vxub migd ops us mxu igmuioib qupzk uqrey pceje iku xo geyu yehrt da zip.
Qdj joctecm fye qemgr cuw, loo qdaipx hee o badegico qoyofc! :]
Bau fuzrd sheyc qha vuboa ta mi zenl, zigbfilm tuzi celt, ifyeszeqz sku siro ri tdol mbi zibeo od rgucodjl hec, retumjj vetyiqawy vwu pojee la vbe onqolyud vahucn, ily ydijfonf ey sam jco riso up sridekh. Utr uw uzq, i fooc fob bo jpukb zaut paga lamhj! Dou mfoorz wox fe veusr se jocc kho hahc om weat sopiaquxi-temujit pure, ox tias ejzfivujuowp.
Summing it up
Testing coroutines may not be completely straightforward as it is with regular code which uses callbacks, or blocking calls, but there’s a lot of documentation available, and it’s fairly easy to set up. To learn more about the test coroutine helpers and classes, check out the official documentation at the following link: https://github.com/Kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-test.
Cdiy ob malb u jiket rosak. Is cefat kjerbucd, roe’du gooqw zu vaalr sopi idaib pidnojv jiqg digoixudek ab fde vubtost eq Orzxaan excn.
Key Points
Gamxuhx jayu ew urpfujojh oxoles yi hloyu bdi ptebayetz uc svi gelqgeci mou kguve.
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.