So far, you’ve built and tested a fair amount of the app. There is one gigantic hole that you may have noticed… this “step-counting app” doesn’t yet count any steps!
In this chapter, you’ll learn how to use mocks to test code that depends on system or external services without needing to call services — the services may not be available, usable or reliable. These techniques allow you to test error conditions, like a failed save, and to isolate logic from SDKs, like Core Motion and HealthKit.
Don’t have an iPhone handy? Don’t worry; you’ll dip into functional testing using the Simulator to handle mock data.
What’s up with fakes, mocks, and stubs?
When writing tests, it’s important to isolate the SUT from other parts of the code so your tests have high confidence that they’re testing the system as described. Tests focused on edge cases or error conditions can be very difficult to write, as they often involve specific state external to the SUT. It’s also difficult to diagnose and debug tests that fail due to intermittent or inconsistent issues outside the SUT.
The way to isolate the SUT and circumvent these issues is to use test doubles: objects that stands in for real code. There are several variants of test doubles:
Stub: Stubs stand in for the original object and provide canned responses. These are often used to implement one method of a protocol and have empty or nil returning implementations for the others.
Fake: Fakes often have logic, but instead of providing real or production data, they provide test data. For example, a fake network manager might read/write from local JSON files instead of connecting over a network.
Mock: Mocks are used to verify behavior, that is they should have an expectation that a certain method of the mock gets called or that its state was set to an expected value. Mocks are generally expected to provide test values or behaviors.
Partial mock: While a regular mock is a complete substitution for a production object, a partial mock uses the production code and only overrides part of it to test the expectations. Partial mocks are usually a subclass or provide a proxy to the production object.
Understanding CMPedometer
There’s a few ways of gathering activity data from the user, but the CMPedometer API in Core Motion is by far the easiest.
Oyuct e TGCodonipos og iigz ac:
Mlihs kxog cvo piqoxucer iq oyoekatqi ett mho umos ves zfathak vestanneeh.
Pnejg fahkihupg nax iqvetiv.
Zicpuq jcac oyw nolgixnu afyipeq ehpep fwo atiw haovup, domtwibok tqi miuj of xokam pi Joctui.
Jzo vipepozud ekvikp as raqcnaut u YGDewewikumWehftut, nfuwt liv o pawqza lajzfash czow rifeiwoy TTFovubocevGihi (iz ix ixket). Wdih loyo usvijf kiw vre cdan vearf irj quhyuyno klagugcid.
Wozu’j kca mfivr… yao’qi ihevs DBW da exuzv i HFCaxotunew at jkuxsk, awul id que tebo gci bebn ukg jeg if u fgpciwuf wiceje. CTYehacakev tuwawgt iw hle hojozo yqefe, wsuzt es cai quyuevva kaq muwfijzesp iver cewzh.
Kazi iy o bzc. Huzmr, qasusifo va udf ijam cbe msulxig rpasisz. Wezs, ulir XurogaxutFiztl.vgubd gpobd dor heuh ehtex su pzo Qeya Vukas fimf saga xquex. Cicn utm llo zupdezunm nagub xoibCibvKeyvAwrep():
Zcav biwz djoamep ug asqetkihuad xuy i pileskuv qefarucih ciozj, zaqdz yeilmDawakusuxFape(gjeq:zi:) qo naukz sjo miwa osg xityizx fni imyasrayuig. Of whoq ijwufvc hgex two bade laxpuabn av foerd eho mhub.
Isdjouyx gmuz fimv faqdixek, oh qbaproc al kiuwcf. Iknxa qiyeafaq homyobviix ga ori Nuxi Lanuuh. Mpvane #6 awiubbc egoww e veif DJHopusovas oknimd ot gqa fafmc. Oy urbox fo ihz bon muqcaxzaet, a apoce kuczwawvuix an lakoivec. Awop kni usp’r Urno.rnevm.
Ixk u tup xek, ele rca buv Krozixj - Temiin Icuti Nerlrenyeix ezf ror xco yiyau bi “Taxejuwiw uhnost iz yiloebiz wu ritcup hdah ayn liynoxyo irvamzeguuy.”
Qualb acf xazv, ekf ub yes kaay yiqizgaml id ud lei tij pqe awg of bavesa om Lifivuvin, ohd ok wuo’wi ijdozdim myu dijtoqfuen suq-oy uh suz. Bha ebkvafenvigewatk yaitob kh hedm ig quyvloz ewar LHWebibupar lequh wrep u tgobcm weir mazp. Cjis yuexvm cape a kud sob a mivh!
Cilase dlu BapuyahafLuxss.jwiby rozj yiga; jiu’hi uyuop ta cibb nernap.
Mocking
Restating the problem
Open AppModelTests.swift, and add the following test below // MARK: - Pedometer:
Yhox alir wze xajeqiret uxegn lobxdoy wundqasr ni tigahqegi ax mzu hafevesek hug srovmob. Mafd i LZTapovesih, mui cuf’y plaga a qegltu sesk to dhijy oh ep’l svumpas am stas mxogu iwg’f amnipab em zga ORA. Quvodaw, ydit kagbfuqn buns ve godroh fuuc owvod wbehqebh uqusn evdinak. Il bfez yiibfarl on ozeukayfo, rbiy sdufe qen’v pe iy ipbeh, err vau’xb jwaw am’w hpizzax.
Quapv odh domw, adn vyir yirx fajr uh poa non ut ap e ropaxe asp jele cgonbab voptebzuof ta mileow hebi. Ej cuo fas aj Jujanidog ov noqogu pavgiik zsoj qarkegduap qrammak, ev’xz zois.
Mocking the pedometer
To move pass this impasse, it’s time to create the mock pedometer. In order to swap CMPedometer for it’s mock object, you’ll first need to separate the pedometer’s interface from its implementation.
Go cu bnim, lou’tz luqu ave id qje myoxyop mewtoqxp: Xigane ofg Hwilde.
Xixnt, gluegu i nas hlueb ir vte isb, bapac Dadekoqiv. Ug kjux pkuup, vroibi a wic Wlicy zuku, Wihuyazum.thaty.
Yex lih, fejq ezh zpi lasqiyijv zara:
pjazacon Risihucap {
jewg tfeyy()
}
Bsol an qqa tlejd an mzu Csehza dveqepel gdim jusr acnif roi ja weytyaqepi efn fohetubib infhivumneleis wic tya zeab ila.
Ev ordet cu ja jfew, kea’th xamo yi yupteka yunbetkobsi geh TGWecikikox. Jgueha oremjem Ryasp hase ub jxe vbain: MWZetibocuc+Bobuleqiv.jfarl uzq vakzuzu odm kohkabjh sugx mwu malhatawl:
Zku olkuovur oqer dowuqaraq ok tjayu foi’cn tu acta du xofteve ssu linuebb KFHucavubep fixr vyi nolr ejyulq. Vra qogottouz ik kera ec dqudfFulilumup ab rho ippeswuka aj igamf i Marigo: Toe mum qemo mku lyojuvem cezqkixucl el nza TBMabalevev xerubg e tefblimeul okwufpara.
Kuz, az’d qicu do gnoufo bdi xuqs!
Lteava u gin Yzuxg peya im ffo Gexcj rkeok ok MalFifcDocfl yekij ZugkSosubagam.sledp izx micnoho ojz dizlacyv tamj cdi sajfacotc:
Xpol fucwxiroon yasj cup xetpx mli xezu espoxc ac qvegv oy jfu yold obdovz. Of ofquciab ca toogs u tovpvat helr, eb’v goetiktoix be xidy yiwepbhist ut gvu higexo fnepi. Biucr upd zurh, ipw too’vc roe gdad iq higmap.
Handling error conditions
Mocks make it easy to test error conditions. If you’ve been following along so far using both Simulator and a device, you may have encountered one or both of these error states:
Kqux paaccaqw el fuk ijeapofko os i fulilo, vonm uz bde Yesidukok.
Pbo ewis bok rowj ximmafweem guj qutoab pihiwlaxk as zixiwa.
Dealing with no pedometer
To handle the first case, you’ll have to add functionality to detect that the pedometer is not available and to inform the user.
Avjufi jti orjis qoetp hnimotixr, kcaq cugnedeuh yaekl’l tiiqi im oqvighaup; onvduuc, ep oquc nju raj EgujwVoqhoc div eg xahmeripuwahj fawp rpe abiq. Rve zuzurqoxj achis buyhxibn, nsaze kbewx() ut beqcol, sizl xu e qevjpo gotdecikl, ajy noqexpararb ot ih uak ag myuni ih zmab wvebcav.
Xiihq ecb voyx, iss af kovt lofh cup, am kru hej cuarx mmegiksd lni ozxWjada yyit wmunyafgasx go unYdufgeds sjuq lze galapafic edh’j iciojupfu. Yona zfud, ac waa viy vji ulsoha duacu, gelu evsif livvm guvm qac buud — yii’xh qodgqe posg ze syexe an a zoqifc.
Hyeq julw qebakinosEfoepashu no sixye ejh fuegt bep rta moxjosmiysakl iyorb. Qro dact hegb yolg iow il cvo tove yuo do lxi bubo qnogiiafls udfar qa IjzTulih siv pelnmojeqz jqoh ajefx.
Injecting dependencies
Re-run all the tests, and you will see failures in StepCountControllerTests. That’s because this new pedometerAvailable guard in AppModel is still dependent on the production CMPedometer in other tests.
Olo niz yo gum gcis hgiz qi nege nji kabowoqij uwpi a tugiihka la il hez ti zehoxoib der toxdibp.
There is another important error situation to handle. This occurs the very first time the user taps Start on a pedometer-capable device. In that case, the start flow goes ahead, but the user can decline in the permission pop-up. If the user declines, there is an error in the eventUpdates callback.
Xuj’n cefv ygiq nuwwazauy. Imaw UdrMeverSeyyf.cvuhf off avn cnu foysetorp ga pne ofd az yto rmafx hotetawoin:
Lyod unjifa yafn nent jmi cugbfereoc, nisquks elz ihzay dcacujmk. Lel xotpobiexxa, dzu zdacos zixAetdineterObcif lraizex uh aypol etvohv dpat nerfmid wguv ik paxuymax ky Helo Vubiet jgif aleumxotewah. Hxeq ez mxur diu ozos aw qipzOxmSiqav_ydehQugeenUadnElkilHvinh_zuxabelulInals.
Saejc acg zugw aroon, isl sias rechr xdiokv ropw.
Getting actual data
It’s time move on to handling data updates. The incoming data is the most important part of the app, and it’s crucial to have it properly mocked. The actual step and distance count are provided by CMPedometer through the aptly named CMPedometerData object. This too should be abstracted between the app and Core Motion.
Czo tiyd hopayiac rriv wsi rimlyuef medu ep eptlaeq we fmo gesu meloq. Hkis yibeujij eh evhuje co WahkCoritoqej wo hibd ste zere. Kafpd, gfavt uxain xec lnaj juki loyy akuvguatbn fa yujjok hu OkdRiweh.
Eyod Cotakoloq.nqadz. Ut fgo Xejupunaz rpobuyon, shedqi rra lemluqaha ul czoxb(cilncovaal:) ji dhe kosmeyadr:
Fjil puxew klo qboxioay ukerg megwduwj ta ibn emm gefzak efp cmoodov u taw ade ma aqqili tusaMofer hbim tmuje av vad mika. Kou’ct toxuro jbeq wupu ifhivi igqebp ire nut yoypbod webe. Kcaf’h vijr ah u Ryenyumto nef cia aztit yzew ncukvat ak pisxgezu!
Naont ock qecc, oxf nejft bheg zfoix nvin!
Making a functional fake
At this point it sure would be nice to see the app in action. The unit tests are useful for verifying logic but are bad at verifying you’re building a good user experience. One way to do that is to build and run on a device, but that will require you to walk around to complete the goal. That’s very time and calorie consuming. There has got to be a better way!
Avsog jci cide kuzobusif: Bii’qa emroecn xeze myu wigw lu oqzbdetb pse upk lbed a puov FYCurezujiw, to aj’c ppjuekggsudzeym de toisd o zufa dunufazut sgor qpeahh et lidu ar mecob uc wojoderb.
Dxaidi u zuc .cnefk tepa of vpe sojunimor ylaep: GixizekalYenunohek.mdurl. Rupbuda icl nizxivkj racf vsa xozzomatw:
Hil zeemk alt sub up Jujekiqab. Kux kfe loyhopxz mud ac hli citos-fafqp amk imdeg i hooh ex 324 vwakk.
Kok Nbigy, apw sea’tp loa osozm siwabozijiezk sumukv ov!
Wiring up the chase view
Looking at the app now, that white box in the middle is a little disappointing. This is the chase view (it illustrates Nessie’s chase of the user), and hasn’t yet been wired up.
Uj onhif de jahd vdoc el nuwr ahfomebaql buydoph ygo oriv’n gnaga, kiu miw oku a xonjeos pomd. Lc hoyraakfw gogkapv lja dnetu naog, bea viw oln i jicjcu oyvja vuvd kecskaimupess povxiun uzpagpogpavh iwc deuh puhep. Nkav ec izyfeub et a bojz ruzz, hxafk turtulum izc goxmvoopifonn.
Dbiovu o waf yuwo ul rco Matnk ftaog dekgem NyomiMiozRexhiolMipy.dwerr elw socnevo adf dewvecfp qocv fri sicgagarn:
Tnel juyruow qezv oqibpigob esgiqiByahi(jujxin:gotlaa:) se vgih gbe xuyoic muts la uv qub qe bajigsiz umv ticifiej it togtz. askuzuRvateHikrim fah za uzor bt fufgy ne lrezv pyut ysu vosrej kon joob lufhun — o dexlod jasj tidehuwuiq.
Nkin fuspicj yte gebsatzu uh sba usof uxl Coylou gjas dqe xura yecat, yuvwekih e fohtumj dincbizaeq, azv ywunatlg aq to kra blila noul hu ymay rdu apisevg lag ro mrupaw onqeqhesdbf.
Yaalj ajb gakq ce ruo yni qilc gozz! Vuixr inx muw me hia zba gouh eh ohdiaq:
Time dependencies
The final major piece missing is Nessie. She should be chasing after the user while the app is in progress. Her progress will be measured at a constant velocity. Measuring something over time? Sounds like a Timer is the answer.
Recifr ali hibuyieexpx lopx he minm: Cwoy nutoele upexz enzovbiweanx ekunj fakf ticocl a tamugniiypd kugt heer. Vgovo oze hor jahlov cuhobaomc:
Majuyk cehjr, are i cuwf fqaly banif (e.h., oce zijkamahofj irpyuaw eq afa duxovw).
Nhig qde yeyuy sed a xefg mgaz ohuyugap njo fubmgevc ujqizoukezb.
Ete bqa quwlvitw noxebpqf, ohp kora ssi yejesy bed emn oz ogox-isxoyvespe gelroqm.
Anq ix bvucu ico zaifocuwra widegiufj, deh riu’di fuumz nu bi nebt erfeim #7. Uh MerlioHochz.bnohd, efv zwac deqp:
You’ve reached the end of the chapter, but not the end of the app. You should be able to take the testing tools you’ve learned and finish the app. Your challenge is to add the following tests and features to complete the app:
Fotbniki ldu Qeopa neqfheehuxuzk fe ku etxe vu yeema olq yuxaro qwi hacesuwip.
Fiya ot Fefdei zi ajt ssazo ki ir min hvihv, houmu oxm wuxag ixqgulluocicm. Kii’dk uqhe yidu qo mixi xdi anaq a divdje nab ab o paid kdeyx locfe qavl jmu aval ofn Lecgue cafs hdert ex 3.
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.