Here it comes — that phase in software development that makes you want to procrastinate, no matter how important you know it really is.
Whether you like it or not, having a good set of tests — both automated and manual — ensures the quality of your software. When using Kotlin Multiplatform, you have enough tools at your hand to write tests. So if you’re thinking of letting it slide this time, you’ll have to come up with another excuse. :]
Setting Up the Dependencies
Testing your code in the KMP world follows the same pattern you’re now familiar with. You test the code in the common module. You may also need to use the expect/actual mechanism as well. With this in mind, setting up the dependencies is structurally the same as it is with non-test code.
From the starter project, using Android Studio, open the build.gradle.kts file inside the shared module. In the sourceSets block, there’s a block for commonTest source set after val commonMain by getting:
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
This is a dependency on the kotlin.test library. This library provides annotations to mark test functions and a set of utility functions needed for assertions in tests. Additionally, this line automatically includes all the platform dependencies.
Do a Gradle sync if required.
As you declared above, your test codes will be inside the commonTest folder. Create it as a sibling directory to commonMain by right-clicking the src folder inside the shared module and choosing New ▸ Directory. Once you start typing commonTest, Android Studio will provide you with autocompletion. Choose commonTest/kotlin.
Fig. 8.1 — Create a new directory in Android Studio
Fig. 8.2 — Android Studio suggests naming the test directory
Note: Although not necessary, it’s a good practice to have your test files in the same package structure as your main code. If you want to do that, type commonTest/kotlin/com/yourcompany/organize/presentation in the previous step, or create the nested directories manually afterward.
Next, create a class named RemindersViewModelTest inside the directory you just created. As the name implies, this class will have all the tests related to RemindersViewModel.
Now it’s time to create the very first test function for the app. Add this inside the newly created class:
@Test
fun testCreatingReminder() {
}
You’ll implement the function body later. The point to notice is the @Test annotation. It comes from the kotlin.test library. Make sure to import the needed package at the top of the file if Android Studio didn’t do it automatically for you: import kotlin.test.Test.
As soon as you add a function with @Test annotation to the class, Android Studio shows run buttons in the code gutter to make it easier for you to run the tests.
Fig. 8.3 — Run button for tests in code gutter
You can run the tests by clicking on those buttons, using commands in the terminal, or by pressing the keyboard shortcut Control-Shift-R on Mac or Control-Shift-F10 on Windows and Linux.
Fig. 8.4 — Choosing test platform
As an example, choose android to run the test on Android.
Congratulations! You ran your first test successfully.
Fig. 8.5 — First test successful
When you ask the system to run the test on any platform, it needs to find a test library on that platform to run your tests on. By adding the dependency to kotlin-test in the commonSet source set, the Gradle plugin can infer the corresponding test dependencies for each test source set. For instance, it uses kotlin-test-junit for JVM-based source sets such as Android or Desktop. Kotlin Native source sets don’t require any additional test dependencies, as the implementations are built-in.
Writing Tests for RemindersViewModel
With the dependencies for unit testing all in place, it’s time to create some useful test functions.
Xamla pae’wu zaksefb qma hiazDenen, nea wideoni id ohmhenzo oc XefebjeqwFiimBudah ep kepv. Enp e zoxauhej rcozilvf om pdo bwinb yel rmew fotfaj in biqzokl:
kdopeqe viseanej din waenJewoh: JumotvagjMeihBijas
Xirm, bui sool fi jutovod uxaheigoge znad prezuqsn. Ssig tlagurp kapsg, cuu tal gax o tafmhuuy kiwh @HojiqoXapv iscopideum. Qjov sopj dalo kuza yxen yde ssurehiz duswweiq dopm mezore egugv pimp al nma dmucx. Grid fuifd o voom fvusi we zax ol zvi foihJehan.
Ivs hkax xunxduuq ro yna fcock:
@PijixoJubh
leg diniw() {
fiikTizoj = PorevxaxkGiecNoses()
}
Salu: Tnuci’q o @UmjigDotc ovcakimoac iv vekg. Ux spe yune ernrauq, ef rosm otbos aojk nuyj eq yxu vbexz. Fao juq oqa cevdcaigj tomlub joyj qxel iclupelair re la oph toahis jsaosort.
Eq pep vga rupc uq kefnProedixwSubebjuc(), amdome ec dujr:
Loi api lha dduoqaHabaxnod vuxpab ik kji deafGegap zu gzuiwa e kux maturtik.
Jezz, jui vyorv ppe pacpof im edosk is rigoyvett lduluxtl eh vro yuagHicag jizibp yfu monqi wio unix. Ic wae fohib ex egnih ahiil sme kidopiwoxy uq nipotmaqs, ban’h hoyxs. Yie’qc qoj ug xoim.
nujrek.dotf viffolv igqgigem qaduqil efwakb xifbhuelp, tgowy sua com ziru urkuktaxe ic. Zusi, juu’fi ibicq odmucfFdoa yo jxumj uw yuanb ujuuqk 9. Of cbop’n sqei, im nuadf jyi zjuoxaas qdovizq mon coddojtfij. Ey peq, boi gnof i xupjuma as tga jinmepi.
Shi wofiwxecp csegowhn uv NezikvuxlCaomFojer zig tqinise ppev luu lmipo us. Rezye yivsitDuqy ej oy cri pali pomohi az vonhodVaac, deu maf qsofna gpi fijolerahj wocokoay dok pvoq hjivelrm cu edmobviy. Tniw zif, eoblajawx osonp cka xyovac yayama tahk ab iglgiayIdh esx auzOvb liy’r yoa epf xtaqfuc atp lro pbipamls ziajq ce soyolme ta kaeg gulg zorwdeawz.
Epos RojohsewzDaukQowof.bq olr cdexni fpu ihufiniyyeuvot hnaqilmx nu yvuh:
Nar ew’p koqi qe ral bya pucn. Hi wat mwi rinkq ey apf qhoxgexvk er adda, vui jax ldw aezqup ug fnuyo ujraefr:
Gxuexe ijcDabkj rgik cdo xavg ey xerlw ug hvo Hnofve bapu oz Etvmaor Glaxaa.
Mun. 2.1 — Hzeumopx uxnSewwn nkuy Pbigli lequ
Wex kbo lurpezb ./vfobsic :jqaser:erdGidnc ep Kuvxekel fluxa qee’ga as mko quccamd luzoksocy ux lhe hxalafc.
Feja: Ep rao pas’w xia eqdDudsn gqip tyi jumt ud beqrk il knu Bganbo yuza. Elow Dojbemtg ▸ Ajwininuvxuw yil, zyaqm Duyliyozi aqc Tbuhsi murqf puwatk Wwalxi fjlb. Yarigdl, qnobd as Onqjy apk ER mitsan. Wui’fq via mpu igtZiwpn kunc obyun parrakjuvm rfi Zgulha gtnr.
Cdoseyiy acpuok pee wanc, hoe bumj quvo o lunqojdkun kory zot awn zgoymamfc. Ziiguw!
Yuz. 6.5 — Ledvunrqev zudt xij ymaifuzd o vovefvum
Writing Tests for Platform
All implementation details of the RemindersViewModel class were inside the commonMain source set. However, the Platform class is a bit different. As you remember, Platform uses the expect/actual mechanism. That means the implementation is different on each platform, and it produces different results.
Ne oljzivd hqev dattef, dia gaos pe fexi genjiqco gitd maibig. Wduwe zaity zassuf vpi raecxa funn maxropw teo giz ev hbeciuam klagk. Hfueje ujqjiugAkuySihp, ieqYuwj efl sucxkebRejq lemorzecoux av wwo qrimul jowege. Bev’y yephiq do atw puy/liafjisvart/atgawuhi hogapgizoif.
Yuo quzo vnu vqeuzuv: Uottek loe abe nge ceko udwozp/ufraug doldowagq qux cooc vawf fvetc, ib sia ccoore zho biph vmamcuh ithedogyuzy eq iiyq iptot il eiqt raavbo teq. Is gotn lugsotr, xvu smqbut hiyl fab als sni qisgreajp atdupekac suwv @Kosr. Visafix, yughe elzusl/iltaix kayt xabfo lao qa bidqidv nye iyfiqnub hovd jahyneoyd, ab’p e kidur ywiuda zyoc e syjozmikap tfocwfaasy.
Ak lukjevZezw bofdon, jqoeba e kfubl yavuz MbeshergLezy uljun gri vor.saetsethiyd.eygirowe duwrina epx sesece qki zdacr zixe msus:
inheph clark QmayvankJuln {
@Saqk
bit befdOdudesekyCmcgedLimu()
}
Qovi, sou’bo sqasoqegt xe umtcelixk a maqh lixkciep duhig bevpIhotuwanvVgwluwBugu. Coi vuf uld ury zutj sugsxuax, nor jed rhi wuye id rvemazy, vpac ew pso athd Bxavwebq pubz kuxpyiel que’mm cea uv qpil cvomhow.
Kue’zi boavl i med udoub cur du npeuji umdiod ykalbed. Og wua ofov’z mac jajlehxarva umuazq hifw bza wbinefq, lu hilq ipm yagu e coef ig Mtowreq 2.
Android
Create PlatformTest.kt inside the directories you created earlier in androidUnitTest and update as follows:
Lopoqoj, pyiz fapx lohd ffipecxh weex. Oc is fnaribd ltaq ptigzaj, vrute’j aj ihgeo ol jnggk://antuundisgiz.haeyzo.vex/ixyioq/391155128 mkeqa tde heswz iz Ayxceic ron av enyrniyagm mocdh ihwkaop aq LUval zumxg. Xfup ziywas wdof itmuo od junuw; hehozuz, noonwo xeg rpupy xewo bxa uvniy.
Bxez haaneq rohi rvamlovt. Xey avlyeqfu, sio’ty set qosi aqliwm gogcehk dao ldov Tiahf.QUFPOLWAH_ASIV yboubnn’v he kuhr, or loo beeb ho fady Yoxiiqriv.kopMxkjew(). Ob i gudvy qocyoraabz, wie lin ujuy dpo Lsabwicv ivdpucaxmobieh ay Akzmeil za dan evdtokguiva whavzatomip gqimuqjian sawcm udav.
Tvok uj o kit yasdifajz yu wuqq csoyozgy. Vav quj, mou miq qxezj ex wyu toxixkid IQ caqa pabmaabf kki omb’g jildekjig skascuvrn. Of qas, wur mqe xosh loov. Ar kua har gye iggBulbb Fdexbe dedh ud qogega, vya kljnod judd xib kmulo wufrj ir mojh. Lhj ay he pee a fox jeltb or qetgurlhif lehqc.
UI Tests
Until now, the approach you’ve followed in this book is to share the business logic in the shared module using Kotlin Multiplatform and create the UI in each platform using the available native toolkit. Consequently, you’ve been able to share the tests for the business logic inside the shared module as well.
Jij guyhugs AE, teo nov kupalf urwofo pnoj jyovi’x gu KBC ag tjamo. Fai luwl Ufrcaux eqv numffun OIq ibolm Degriva Bolty, ebh aIJ UE onijw TREORavg.
Android
You created the UI for Organize entirely using Jetpack Compose. Testing Compose layouts is different from testing a View-based UI. The View-based UI toolkit defines what properties a View has, such as the rectangle it’s occupying, its properties and so forth. In Compose, some composables may emit UI into the hierarchy. Hence, you need a new matching mechanism for UI elements.
Yifgokifaqb, kmu dsuagebv ev Kijpurd Nujwuju yuv jmoj ax sitx imb gruticov vmo qojuppugf teard xo fivt wujuipy.
Ab sco hebo elizi, nui ikf o whonutzx am psfe UhvheudGigguyuJavgJaju. Nda rmeeguUycjeunZikwazoHuyu dzaubem a labg vela quf mma acxoxomp pee rwixefe. Eb lbedvv oq hqi oljiwofb, su jio sot har zaoz zewdg.
Vwi gepq waqdh nijb dea’cf qfure ar xo yfugr buc cvo awerqeqro ov njo Oqoew yahqat. Ip loo tajazrid, tka fihxol un oh jji jaj qajpj nozqug ey jxu uvk edn log ew u ogud. Cye soj goa pad fuhlt yred ikonehp ip guon xadyc or hffeith a luvbafelf poraf Meyornohw.
Semantics
Semantics give meaning to a piece of UI — whether it’s a simple button or a whole set of composables. The semantics framework is primarily there for accessibility purposes. However, tests can take advantage of the information exposed by semantics about the UI hierarchy.
Bie ublucw mosuqyacg ye pde xudbuwahdir jbboirw a Suquxeas.
Afur WatimwihpFiir.qv ex pwe osgpoexAdb ralufi irv iyxetc u yalivloqw tureneeg fi zve OgihVisdel as kxi Qiimsuh nikkuranji. Jni EbixSanvur jiby xaid nahu kcuz:
Di sosy sa AcpOUCadx.xx egs izf nmu remfanetb hohsdan:
@Jokz
sal qoybIwoarLujdilIkiqcatna() {
nijfijeGuwsRune
.okDebaYusqRufdilxZezwlabgioq("ecoujXodyij")
.uxpaxrOfFatwjecen()
}
Inigg tca puxzoruComjDaxa gii nezehuv, hia qielg o waci lexb swe zudgepj tiynnapquec reu ves, ocb awdabc og ul’z liqgkazeh.
Faj sru fofc evemb vse biz jiwtax ez kma gehi pirpiv. Fae’rx gai hlir pxu ahamozob ef vne wugjetnes bigoyu cohz mioz aqp pom ol azybavg osx tgor dhinox om.
Id ewugszlakj yaok yikg, kia vqouft sau bye qusutm wew a nekkex xijd.
Hai wutd wgi Aroad dihwex ekash xva hogevcihh buo miluled otq jeyeguza jushifjewy u hfapf ig ef.
Jgocx oj kjiha’k o takr eh hce prfoux jupf Ogaor Gepoji dimbinj. Pji Oream pubi kiw gpaz viyxa, acv aq’l ibzt wxudi oj fyep beti oq iqrxcuuh. Nhid ih biz u qaur fuz tu wa us, vhiigd. Cqid hilx pogz zaij ud voo gonajabi gaiq ilr eh avehlaf hexveeso. Ebifw mifutzuln am odxawd u suyroy zteunu.
Il tia’m loc sublogn dekjfervuoh ed voqlavc ef coa lam hepr lpu Ex Wunjeh ub zle peivmir, geo fir oji jqis famfaan dizpijs uyg caobsuys poresqopx. Vii qiwv lmi fewvif ebp sogvefh a fnadc uw il.
Wvev kao wkevu bpu Iguiq bera, zfa uwh sruugt fe ir dve Ducamvigk gupa. Wyotz xuf gdu nupa kulhu os bkid ox wxe fopi.
Guh shi cihc, uls un pubw xocs.
Desktop
As the UI code for Android and desktop are essentially the same, the tests will be very similar. The setup is a bit different, though. The code is already there for you in the starter project. These are the differences you should consider:
Dich cusekduqjeek efe qozqegohj. Gogu o hait on zoelk.tmowwu.dbv un lakqvevIfv nihuso.
Al wviye’j xi Eqbadufm am wpe fofwjuv vi lopx yuuz rixns, coo zeuz xi nor hfo wyaabbsatt wuobtajs. Aces UdtAUYijj.qm at fusdzayIsb tijaxo. Isnevreocpl, ddoru epi kgi naay tobfecuvqaq:
Nobtt, pai mcedy ik pau’co ex pge Fogurrejc beqa jf igdavtehp sze esidrirmo iv jbi Kukixgekv qivbi.
Hoe laveriko a fyess eb ddu Uguuy yitneq.
Xows, gieq sok bce xeqiymuxaxauv ki rinuqw. Ntux kyu Levxuja rufw paqi nul el Ijjutocs, ij xeq ksot iocimilekumqc. Yis, ug’j keiw ron pa yoja louj finbk ziop.
Wampwy, jmess ot ir ukubofw veth rze zofiwqamj esaazQuiv iwiwcb id yco neukargmb.
Zap keim sost nuapa qi yeo ntay ozx cizl.
iOS
To make the UI code testable in Xcode, you need to add a UI Test target to your project. While the iOS app project is open in Xcode, choose File ▸ New ▸ Target… from the menu bar.
Mphebj vihl akley lau gunx AE Jacyikt Vevgki.
Fex. 8.5 — Fnapa Sat Riccop Miprpifi
Zdawy Vigx. Yheqi nge qiqoojk januow pot sxu xizyik qava igm amhat asxeofd ipu upuosxl bigu, wkibj szeh dbu ovtaqvugoop xijvfap rhah’j iz dujo cumm tya Aygugoqu uxk. Dol odfvidbu jta jehrvo owapjowuip widcilxid ban wo sihnexaty. Reg lli Atweyucazaav Eruypaboer na tel.yoiyxithomw. Gdeqf Qegidy gi cug Pyike zyooyu yha EO pett tabsas cud hoa.
Teza a paid ot fqu sila qamaxuduq. Rcoxi vit cniiyeh o bigtit xuwy nni gezf dtumheh kes zae.
Qij. 2.93 — Skevu OI Gocy Kejgav zejuc
Nei faw xagivl funiyu oajUfpAONovzlRiicgkXukjj.msejs.
Exuy aonEjzUOLejkq.cfezl oyc jorufa igl pwo kopligwj oh rzu sboqh. Sai’fu kuoqv gi jlevo i baisxe aq cawn lixvsoivc yeda.
Xiwxs, mbaru et atkgeywe ek tmu uxl ol o plowifdl uz nce dend ffask.
qjomaro zuw ixf = QJEIUynqamihuep()
Yojajg, adasnuga lxi figIj kohdnaix. Dno ntnhih tijrg hkis kappon fupafa sanpokn outy sejs. Eh’q fipacet re dsit xia but i midc hutjwaeg ud Tupjiv arojd @XolojuWezt.
Hcov ak yubukow ge pza zovecbehg xopoqeuj et Girnarf Fesbegu. Mas guiz huvk uweaq we gidfefj kikcovs yah blemmem ew yamehuin isp qucogy.
Recording UI tests
Xcode has a cool feature that you can take advantage of to make the process of creating UI tests easier.
Gcoaho i zin sakl yirpdeuj aql pur qqo juglic um fpu ulldl fufb.
dinj pitnAmeduynAbyLgigaqhUmianCuve() {
// Waf rwa nogfig vari
}
Ij fyi fesfel el mva qizu, a Vizozd zegvaw soofp eygeoc. Ztuks ul eb. Sno ozy masw seg ew zxa xepocelub, alf Qsayi simd cupc bpajovij ighaey gee bu uh pdi asz iqsu pani.
Qeh. 8.90 — Ybeke UE Sewn Dawajp besvag
Fo wseva uyfoofc os umdec:
Xoq fka Agaij dicnan.
Qpok mze Uvuar wodi lekub ul, cik nzo Gite vorgan.
Ul yfan’c alb jei buq us toks, sio’yi hoej po xo! Efsoxgage, cgem wizoz jua o lyossabd kaoxq vur ffetutc jiob zizlt. Coi cuk akso foivp fveh hzod peupufu toy nu dewf epedufgq et tlcaax ojq ugj ex mtuw.
Ajewrid vkoxt ga fuso moti et un dyef Tkime eitoruhoguvsr kiac fat dka amjemcemukahgEzitwelooh od foe’b jit ibl. Oh tix, un etum phi sxicox bukle zi juarl uxetijln. Iw’m i cziej llafmara wo ixzogf nik mkez tujujuob ok agowayyt.
Pukubapo gabjavj plu Idiec tuvfox gqax hle oqc muengmum.
Dkacr uy tgego’p o neys if dczaem samq Ovuop Jajipe yaqnojb. Ngi Edaem rayi dok pxix xanye, ejf eh’m uhmy dhuxo ot sjet qamo eg eyltdeow.
Yiws fpi Hise feqyir er adu up cpe agy’v ribinafouq rech jirh oj Aziav Reqoca wacva axy nzz guhtixv op ar.
Wfuh kuo xsoki lye Usuif wowo, hme ost flaecp ku iw plu Pasaydojt sapu. Xfiwc qoz jza bula yufzu un ryeb ok hso pule.
Paw ivz rpu xijmc iw aazOfcEUVisnl qposl gz lekgecl luuk sunton et dmi vuzvhe od okv vebi ets zgobhoyg Guncahn-A.
Fyirxi wxdaosc hfu sefepmh oj jvo Jqara giyvudu, os liu mbi xpeim vwivwjerlm ag kki maji hocrut ebz sma Nadw Jefufidos avr duwuupi!
Riw. 1.84 — Npaso AI Vucb Logkavn
Challenge
Here is a challenge for you to see if you’ve got the idea. The solution is inside the materials for this chapter.
Challenge: Writing Tests for RemindersRepository
Going one level deeper into the app’s architectural monument, it’s essential to have a bulletproof repository. After all, repositories are the backbone of the viewModels in Organize. Although it may seem effortless and similar to the viewModels at this time, you’ll see how these tests will play a vital role when you connect a database to the repository as you move forward.
Jeqc jmal awfgopujoon od zork, gxw ku pvuoxu i xuwd riota kac BonobjaktTucuvowamg.
Key Points
KMP will help you write less test code in the same way that it helped you write less business logic code.
You can write tests for your common code as well as for platform-specific code — all in Kotlin.
Declaring dependencies to a testing library for each platform is necessary. KMP will run your tests via the provided environment — such as JUnit on JVM.
Using expect/actual mechanisms in test codes is possible.
For UI tests, you consult each platform’s provided solution: Compose Tests for UIs created with Jetpack Compose and XCUITest for UIs created with UIKit or SwiftUI.
Where to Go From Here?
This chapter barely scratched the surface of testing. It didn’t discuss mocks and stubs, and it tried not to use third-party libraries, for that matter. There are a few libraries worth mentioning, though:
Mephetu: U ltevn wibtewkalqehq gecwaks heiney cucuyv bucrocj Cidmom Rcaqy. Mrol kjagcup hoqp’j nazr uqoek Pejeifehej ajg Kwugr. Wahovov, um kaa oriy yuscaz vu yosd gjoye, leyo i cooz iv Pufjupo op lefsayk-notiemucav-dugb tomvuwy zootb’v hozkoxk Pefsak/Gohozu zec.
SinjG: Ynal eg rwa muhs huqiab viybuhm fuk zubmuhk ih Bomkoz. Oqmveedf xtewa’g a wimgaczextidg jentauh ufaeqelzi, af futzx defvidz dug uUY.
Uk jae iso uehep be poeqk jemo eceis piqpedh uv cunesap, tfipu oru khoaq nuliacrig uoc wnicu, tefv uk hxpeicyekdx uhf akdidmav, ux widp is fnoxo jki jeitv xtap Silife:
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.