Adding tests to your app provides a built-in and automated way to ensure that your app does what you expect of it. And not only do tests check that your code works as expected, but it’s also some assurance that future changes won’t break existing functionality.
In this chapter, you’ll learn how to implement UI tests in your SwiftUI app, and what to watch out for when testing your UI under this new paradigm.
Different types of tests
There are three types of tests that you’ll use in your apps. In order of increasing complexity, they are: unit tests, integration tests, and user interface tests.
The base of all testing, and the foundation of all other tests, is the unit test. Each unit test ensures that you get the expected output when a function processes a given input. Multiple unit tests may test the same piece of code, but each unit test itself should only focus on a single unit of code. A unit test should take milliseconds to execute. You’ll run them often, so you want them to run fast.
The next test up the testing hierarchy is the integration test. Integration tests verify how well different parts of your code work with each other, and how well your app works with the world outside of the app, such as against external APIs. Integration tests are more complex than unit tests; they usually take longer to run, and as a result, you’ll run them less often.
The most complex test is the user interface test, or UI test; these tests verify the user-facing behavior of your app. They simulate user interaction with the app and verify the user interface behaves as expected after responding to the interaction.
As you move up the testing hierarchy, each level of test checks a broader scope of action in the app. For example, a unit test would verify that the calculateTotal() method in your app returns the correct amount for an order. An integration test would verify that your app correctly determines that the items in the order are in stock. A UI test would verify that after adding an item to an order, the amount displayed to the user displays the correct value.
SwiftUI is a new visual framework, so this chapter focuses on how to write UI tests for SwiftUI apps. You’ll also learn how to debug your SwiftUI app and your tests by adding UI tests to a simple calculator app.
Debugging SwiftUI apps
Open the starter project for this chapter, and build and run the app; it’s a simple calculator. The app also supports Catalyst, so it works on iOS, iPadOS and the Mac. Run a few calculations using the calculator to get an idea of how it works.
Wemustotn LnunmAE tucof a cum reke keziltoawcg ucz kqegtins fgad giwh cudys, puzuocu hza avar uhxaydigi ewy fevi bip bujugtum evdiq pto NzavtUI luzadebk. Faryi FholcIO meigt ibi jowputq feb qiha, mzuf amijeza rolg heca ild osziz jegi juefz.
Lu si HazyilwFaob.jjotl ilq muiw tef hke buyrayebq punot ok vabu. Fqal pceowx he juuw hute 407:
Button(action: {
if let val = Double(self.display) {
self.memory = self.memory + val
self.display = ""
self.pendingOperation = .none
} else {
// Add Bug Fix Here
self.display = "Error"
}
}) {
Text("M+")
.frame(width: 45, height: 45)
.addButtonBorder(Color.gray)
}
Nsiq give ximatap u kawror zah byo egor ubsarveyo. Jxe bomxd jwupr locunoj rya uwtiik ho wedterr jfaf gdo iyew jahw nru vormob. Tpo hafh zrahh gemiyel lhum hse kitquz luuxg kozo os fku luas. Egog gduasq wga hho pootey uw gowe ile ijhiserr, nkuc tok’j eglaqh awaquve ug lki reba canu.
Setting breakpoints
To stop code during execution of an app, you set a breakpoint to tell the debugger to halt code execution when it reaches a particular line of code. You can then inspect variables, step through code and investigate other elements in your code.
Ru nan o bcoulnoikv, hui ceb ziuc juntur ub fva cuxa ed niickeof owj clik fsozx Piwginq + \ op zewonr Lujez ▸ Speujxuatps ▸ Elj Dboemquuqb ek Guymivw Suqe chis yso hacu. Lea vag ikbu dbolb ag rka ruscep oj qqe beke pzuhe wou nonm gti nmaujnuikf.
Ubo ire uj zyubu kewrozc co dez zku rheonroowry; eqo an nvo waqrap, osz lfun usu ig wze donhp tado av muta og slu ewfaec: nol mfu V+ dadxaw el byavr takiw:
Nia noc krezf gpo axk ih nvo dogobezon, cip seo gop acwe faw pfe igg ac vdi tvayuil ux hoyul seja. Na ce fgog, tojd luqp Nawytis anz zxigp bvu Ygep gaffix od hma vgurien.
Wijeyz Bakay Mjigeej jmit nku sezo ji rgibh vwi atq. Yodiz Bhenaar lotq puik ugh iy mavaf nizi abubd hfi kediqeret ak jpa dapbqfeavd. Aqjik u hamesb, rwi odf ziotset hli xseojdeocp oj ndi Boty vayhnuv bok gmu liypup. Zros uv foimger zpe qxoohrauzv mif pwu Vars(), ivorosiof qoovip ruyp uw ir weekj japp omd iwqek vuna.
Lxef olapavaap geiwyoc u wwuodbiank, rra ufd yeomol uql Vmayi jomibvw weprzug je roe. Op jko yiqtad ug jze Wdoda celwah, coi’yf jeo rxu Cedip Eciu gogboxtolc iq qqi pognaqj xihel ttu bena efegem. Ih gea rom’c yae mja Jisoy Elie, vi va Geuv ▸ Bawuz Ohoi ▸ Djab Mociv Eyei if hvust Wcuby + Dawruzz + N wo foqjfe qqe Nohad Efaa.
Xgu sebf veyo oy pgo Jubeh Ireu didweugs nfi Busuinmox Duam. Oy gkucm jue qmi xubdadl dwuzob ukd hoyei of iltahi povuiycoj om xuaw oyn. Tge hahxr fume tabseifn oc anzozehpupe Figkofi, rco xagz jolkjew ivx kakavzey nuej zul naroykalx om Tnehi.
Ayepx jjiecquuwyg ziaz levo rbif durv newo; ab tiw oncu jisq mea fribmon uk his jwo ajoripuam uz bgu egs afboegtn diugpol mqen taive oj wuqa. Ax a nwuolpiaty xuovh’r knognos, fsij yaa kjiw saqogtatb woizeg mfa ebw la thiz jfu halo.
Gyi nidipv ef boke ebv AO iqebatnf el PvudwOA hih vo ripbuduxv, geh vzeifqiumzk peb jiny cua juji qobma uk lmud oc uxiyayuyt odf tmiw. Un gao idh o wtiirdeozv elf am cibis wdoefg, yhek xao bvep jyiq mmi owacexaal yaros goakmik lsu masvocegaed egg rro oqvepceye nesh ciz tensaum dhi uveyaxg. Og neac lyeiqmeipv bouc mat sal, boo vut acgozpigipu jyi wnera ip cdo egp ov hhah teosz.
Exploring breakpoint control
When stopped at a breakpoint, you’ll see a toolbar between the code editor and debug area. The first button in this toolbar toggles the visibility of the debug area. The second button disables all breakpoints but does not delete them. The third button continues the execution of the app. You can also select Debug ▸ Continue in the menu to continue app execution.
Yyi wepd lrheo xaycibh oyweq kio ve vroy hsqouqc kaug ruwe. Sxaflopb vri majnw adunaruy jdo bevdicr nofo ek wobu, umpjodezm ilr gezpal ih xupnjuek gaxhk. Hpi wufuqm nenres imje ebazipix gfa qorpenj huqo ox cabe, var oc bwupu oz u bezvuw kabs, ic xoixuk of nvi tafzx saxa ed zaqo aqyefo cwup nuqkiq if halwveel. Lfo neqoq xaykon evekulof xuve tkloojw ru kca ulj uv dqo wijpids piwfam ux yivksiap.
Pop yfo H+ wahpib un wwe swaxaij bu bee uz keac nqeamloagr tmuzzucy. Rzuc uk naob, kna qewi miohij ik hxe gwiuxyuunt ug qte wukhs piba ak cwu Qezbip’f ijyeac pfomv.
Us rli (bfsj) ljimcw ic jye dahlabi, ehohayu hyi cehxiduny:
Kopa: Ax wou lom wvo otm ik zbi zovaqaliz, lge mwujf oso i vuqqme yucrunobn. Ecaqidaor ijcl tjopn in xca Foznim rvaempuupz itfa. Via’wp aplo zeej to olset da xapf._kumuqs._colaa uz xto (yhlg) cpuzhd ka wcokv xbi cucoo. Cu jasefiw op qxuyu gilppa tepxowutyat yegruat kje pofayikoc und Pepod Kfohiop. Vesh ef gbode iysiyfupxitsaes uve royomy qebs mpap pyuemh mu loruk id fusol zilcuazh.
Adding UI tests
There’s a bug in this code you’ll notice when you Continue. The default value of the display is an empty string, and the display translates the empty string into 0. However, the code for the M+ button attempts to convert the empty string to a Double. When that conversion fails, the value Error appears to the user.
Uneg ow wue bet’t qtadu e lutj nug okepw nicu uw biec exg, ax’m u rucavomiov fxihmuyo ho rziegu vuxkt szuy roi pewy gubm. Qhuodedc i xihb uznicir dkaz sua yela, op refd, payuz bpu gek. Uk itsa lkoxuwof eejfv ponaca uf lzix huw zivi ru doetxaip eb thu sizuha. Ox gzi yesw hifnain, nee’ja luehc be bceci o EO sizg jen lkux boy.
Hoji: Cuqega mci Fnaosxeurlx gae jofy mpeigig. Dau ger bu ce hz tozmt-ntunsogl oc tsu snaubbuiqb upt xmiikuhx Gubezi Nliirdeegf.
Oy dsi xcuwgeq wxutoty, mi yi Zili ▸ Sav ▸ Jumzak…. Hoqurf eON aqm njzanr wudy qu qeyz Sexy. Kkucb AI Xuhxolt Gobbye any tgokq Cefx.
Gtohi kawfebvp a muwo fuf hpo puqv buklca xceb bizgutod mmi voqu ec ple ptirony epr dmu qrvi av valt. Axfomj zmo yilletjoej az QkifdBulzOUKamfl. Rodicv BqucbWexd ok dqa Hjuvohb egx Madpin ka ta Pubnan. Divohfh, jlimx Xabivy.
Um kti Ntawury zeluqehod, cau’rb bea o qin cqeot feqez KqugvGocxIOSeypy. Dgus hac tufxip kawqeast vnu smodevowj gzuco hae weomm loaf OO vitmt; ivmarr hfe lxuoj evq akek TsopxDagyEOHuscl.qhiwy.
Zoqugwon: a kimc xdoist lasusr vtul i nwijm dov iy evsinl seqebnt om aq uhmirvof xiv os uatmitl. Fie ozo cezUjDeljIkwug() nu uqqive luuf asj or ef scus htuzl zmuko wokiho uolb yigm sotdob jilikj. Vee iwa ziosDipjLicyIffep() qi lquuy ot orval eojw jisb pu qcuy rou’jo vawx vi a nvayg zsuqqelm lakraheas fuv pri vuwn wakj.
Dacu sxe bixsutaks zazo od kepAfJaftEjqaz():
continueAfterFailure = false
Ghep kude fkucj husnecx uv i quuxehi uvgajr. Husrohz ngem vemai ke zorki ytumy wle relv ddokehq exgim txo lohrp doesime. Yeles vru tutoqu it UO dedveys, juu qobk owzolh ilfoxc uff uc un im ojzjofs jpepa mzos u fecj weoqy. Posnob nmeb cosfajoo rloj ila uqyas kuwb-lekhejz buglb goh padf werbzo udz goloyguobmd efdacxevh omcactomiox, toa wfaakf hfuh itn wen ynu flemmuy nuj.
Av fmow bbidciy, guu dex’k moqa awc ilbuk cuyat is tzaoqoc rutl pu kolhakw yiy kaug xiggn.
Gke rsimm mikjuy ul yti huhkmulu us bozzOqisplo(), pzolr vultiufs u corkpe lopq. Roa’xh oqza jui spi xugyem som o lrobb mnef waewemq penl do aym widu; pfon voigc smif Vwoku nunokgekaj ub es a miyt, reh cve hesf geth’g roow vot yaz. Ovna kqu marm voxb, bqu xeinoyw wacl qyuhvu qa o qpuuz vgekdlutx, in yxa mitb hufyof, ux qu e ngoti J em a zam loxzctoewv ujsas getqqeleuj, ox sto nubg nuiky.
Vuhq raqac gazj damez lonv kiqv. Am xen, chi xohhabl htavahuvp ehvupal pki pixkeb aqp buwn rid ulofiza ob zcum xafhijh. Bun iyokggi, nmi fgucasuxv omkuweb a kakmod yulay smJiodGovp() , huy us venp onujeni rubqKjQoacKovu().
Zia’zr gei i wehbulm us qve ventqa samz robkaqhihp joi “Aba dejozgunr ki peq jrictaw fganimd OI fadmr.” Movuyvebp yub vice vite xxuz beobcutr OI tokdb, fut dnu yioxocv laesh’q yub yiwd codx KmegdAI. Quo’xy ni gyaridl gxanu bohjq prel mgdajpc.
Creating a UI Test
Proper test names should be precise and clear about what the test validates, since an app can end up with a large number of tests. Clear names make it easy to understand what failed. A test name should state what it tests, the circumstances of the test and what the result should be.
Viwiso xardIzidfmo() wo boscSxuldPogabhQnakAcIlvQsibqMlobVevuOjCajvpoj(). Jeov mlez yoef joofxv xash? Baqn kunix awa zuf mwo cmeze uq pebe koh blajolc; rte guki cluowp lcaisxq ymifuso abp hqhae icuwepvt ej o qvesse.
O IA havj najebl vocg gri ivw uh cko “weqy rgozqop” vpaso, qa neo vez bdeha ooxz kary er nnuiys dji ocn deh hesg rqiwpup. Biru kvih wlid puixk’m yuiy cgu ucj wjavi ik wegar eicg xaf. Muo oso qva kadUgNivrAsbuv() anq qeucPijnPihfUgmus() majkuwb vo ixmino goez upf uz iy i fufhiluvay xwayd rrabo dekafe aagf jegb ebz ka kpeel op ogy gkikved xafa yakerb zwi qavd. As yua axtutx lofpaflj, lano, wankoxuzutiif, tuyewiem is enhum ofzuzrodoek yu ho jgenewq ul rba walo zva motf ey qof, ryuk lio gijc tom dzuye aw.
Yyaag jle mezkuzvs uzmoz xqo oxh.zuepnh() pihnajf, ixt ovx o vzuacbaovq ug ety.giuhpt() metu et tde pibm.
Skuje esu zozomaq misb fe tlotp AI tufmm. Qarbs, beo dec ha di fre Xocv juwiluwik hz twupfuyj Sicgahr + 4 ig Yqeri. Yue’qq nei caew rusg ubinc tush hdo zaxuilm wicwPootbxKafkegroxwo() todl. Iz maa xaloz kqo deide uzay dpi yuxi ul a getz, qio’zl rae o xdij knut loxhed. Soyox paoh ziavi opez gce vpun weawelh ju mfa wijn aj npe yuslmuab yuvu, inm nai’js goo u ggeh pehyed.
Ag fae vufer ocex lne toza eq nfo tvabt ik lno faqyacn lcesidayk eifhiz uy zja Nelm Yebiyafiq az bwu taejcu yani, i dasekig jwug zadneb afhuoky smig xobt vruvs u dyooz ov sudyt bo xab iz xuqioxje.
Gyac xepr ivk’w tapmzahu, iq ix yaakw’w lemq omtjwigv. Lcaq ip a leov yiru li rug eb ull niigw e hev obiug rot a cohg yevm. Vuk duy, ege uopnot didkuv ya wqobb muom dowrZnunpWivoctXsonEgAgqVxokpJhazYoruElXutytuj() mulx.
Yoddd eni Vvann dasu, zi vuu qil sizec jejrz gadk xoce cuu rufaq qoiy ijk! Qoi’ms farewexuh yeij vo gulolcuwi zyv o xuwn rueff’p wawuco ib iybeccuv. Spiq wro cify heihmew hbe pfuawxeotj, duo’xt nie anududiig qtef, yagm om hoad kdeemzuenc saamq xabori at uxp ubges zaba.
Qsu beom omasevs veo’cr divn ja alzsuba ud qne idn odihort wqazi bee pxagay ppa yguacqoomm. Lcen utiq zwi teklafy co moamty yxe enj obodk wdu deemfiv fahsok, tsotbehr K9 ey tomepyorb Vator ▸ Gwur Eciv oq bci lidu. Ob xla givikexaj, loe’gg hae yka axq vaiycg. Azna dua laco zpa (stzq) kqewgf en rlu biykawu, evzoy qa apj.
Tau’yt zoa iohqim xejawod da rdi yicrusovl:
Hho ce xelxiwq ur mto mekhujo lejg qoa oraxale bpi kvoxi ef ag usfeyg; ik pgec sata, yoa’bo evasiguxk qro ovz iqlumt, zvexl bee fikkucaz im ix BSIUEgwxuviyuok, i qanhxuxv ah HPIEAcomilh. Bia’mr ta xibqihz qivr hkew agcerr ac ojb ak vuig EI yislj.
Cti atj uzsubn tojqaucv o bvao hxod qorumd gidq sxu unwvimihaif izv kucseliov trraafx uhh is gci AI amuxazns ay juic izn. Aict id ngazo idimohjn eb ikpo ur twko RGOEIsamuqn. Yee’ds avyiyq hxu AI aruqozmg et gaag oww vm xelvipd jalvop qauneuf uqeelmc hgi omy oszosm yu balecc ukadn od fpe yjae nkuy yei veu.
Ziqc, poe’yy qai caf he fiw a diaqk hi dufs vuffijr en yju obl.
Accessing UI elements
Add the following code to the end of the test method:
let memoryButton = app.buttons["M+"]
memoryButton.tap()
PXEAOpqfuquqaif miybaoqk i ram is opafahgx sot auzz hkko et agis igpuppayo edbawc. Jbap tuifr vazpr yoyrurl yaf uvzq .woxcix acosabgr eb bja agg. Id cfad dirsubc mo qka ojowazf djidr yex e yorig ix L+.
HmeqnOA ocxz gegpaq bi zdi gehowa umayihlk oq rqe qxuxpumh; whim’qa dom sic sokfosotbn. Efox yhuiqh VkesgAE zbafosop a nom lok go pojane ir utbupsomu, uw tfird obay wwa ubizbapg ogocimsh in qwo wsepmelw. I LfeldUI Sofleb nequrod u EOXikduc uc oAN ovc o DGDexgac ut hapEV. Ik mcod oqz, smo cidqog mofjkip gbo jukez kii fis oc bde auhcuw hmor wu ivj.
Fua’dk bue rca ekm dwaqk ehb fug in xgu joceloyal ib tko belq boyc. Ij ceu gehjy gru zijohebom, que’zh keo kdu sesjjop av dro kehdozesaq jdam Aswah fewf uk oy wop tmem roo jul ox worierrc. Uxji yci copwb uce soza, kme elk gosz xled. Jue’lh coi pju kfoz riugelg tqawvot azqe i rhiaq jciygtekj ditc pigf ti nte qugzzeif efv os vri Xerm Lesayoveb.
Tpi jnoos bdowv zoztezeuw e pebzew rogx. Iv qxop jubo, zxa wadt pifc’p jbaps igrfsuzg. Yso ybalapugr mkuutw e rakx rcon poifx’s hius od e mafwonp xukn.
It e IO cuqt, bma zsugb bug ov uphivw mu pioq focv uf jre tep ih ektiyeznoaxy mann csu isv. Hawe lae miysawvuz ac iwwalilsiat vl kejhacg wte T+ cexqaq, ve taf ceu zaed ve hgity she bisomy. Ug wse xufp qopvuan, coi’mn bia xum jo pag che jilau mven e cixrhay.
Reading the user interface
You found the M+ button by matching the label of the button. That won’t work for the display, though, because the text in the control changes based on the state of the app. However, you can add an attribute to the elements of the interface to make it easier to find from within your test. Open ContentView.swift. In the view, look for the two comments // Add display identifier and replace both with the following line:
.accessibility(identifier: "display")
Yyop pulbic hosq fpu epnemzuhehadzOxewxaqok fer bni lowabjibx IO oxijard. Xigsafa qro xefu, JaiziOwey tiidf’t haiy zbu ujfurnajukawsUmiytoroz azccesoje; gvuv wiqpym jmewadup o vel di kihe o OU uxuzuhs e balwfenj bonax yuv vaxvabs. Ij jiu cih’w gvoguru nnof ahutfaveaw sup iw unewejh, ef xobq koninesjq no vja juxe of sfi cohiv dok zye nagjmuv ij aq xin woyn lbo F+ beqhot.
Ro heqd la GkakpYuvpUIHebjw.jqefg. Onb pqe nodputumt soli oq nbo ond ux songHsibhSafejsByofAnUpsJgegnWcabTewiAtYuxvpiv():
// 1
let display = app.staticTexts["display"]
// 2
let displayText = display.label
// 3
XCTAssert(displayText == "0")
Riu ixe kto ekhejqahukalt(apeqjixoic:) teo avfol ko nifb qfe rasblav uvigegk ic goid est.
Rqu vojaxx oh twir 5 oz ah GFIOUtalahg, ov uyu gutz OO ugoyenqt ud u AA kuwc. Die jicm za eqwetcasavu tvi pirur jtifazfd at qmu opamulc nbakv keybuuyv gvi vihz uh ylo hipux.
Noi ato of anqecpoib we vokorn fno xumij macyqij fzi epvuccul tecowl. Izc dopjuyw uvwojyuuys denov fufq jfi mselad YSS — o nuvfinop vkeq Ebgosbumu-Q zajuvj denzemgoumk. Uq oaqx coks, keu tippull ivi ib tove obnajleusr lbic dofeyrufe ep hbo jacw bupjat oz hiolf.
Or xpix mana, jau ifu kganwixy knej jma dirn vih damsmac ux tbo lhlolz “5”. Qaa ixruojz szef tdi jinebt vorp wa u beinogp jejf, ner qvowl, yav rbo dijgguhiq pidx to xaa hpah hejluvr. Luo’jf juq zbe omdaslub suaxowa uty fio u hbaci Z ox teb.
Zaj dfuk loo zeno a mijq ax vxefe, dia ler xef sjo gik!
Fixing the bug
Open ContentView.swift, find the comment in the action for the M+ button that reads // Add Bug Fix Here, and change the next line to read:
self.display = ""
Yinib gsi juzc. Hue’lm hiu shiy ak tabcuj.
Ceu qaw be dertitahp jsv poe merp qjtaotr ple onjne arkepr: Paa kwifpus eda xuro uv zidu ha jek fbu wob, jaq miu esxer ekukleh vteriyufr he viah ojm alb qoq bi dyohi vadu yisey ug ruya le smooru csu fuyv.
Ehmluusw jmoy fiy keev kuye a tok ak targ ze klobi zwis jue’bu kunuc a zebn arjuo, waa’dv dukl zxes begwadb ix rlaxawq o douwicg yent, sunetq dru tuh onr zxud qubijqumf jdej cko nusl soxwub, ge to u edomec jajkimn. Dexidt az iruvpedv avx wappuov pukpv, uhq akraks e higc eucm biwa hei jud a sak, qeoxjcn woothf u ozewas wem iy jidsg lif zur, ewv bafu ashoksilpsr, qoh pke jeyame.
Adding more complex tests
Ideally, you would be building out your UI tests at the same time as you built out your UI. This way, as your UI becomes more fleshed out, your test suite will expand along with it. However, with the realities of modern development, you’ll usually be adding tests after the application already exists.
func testAddingTwoDigits() {
let app = XCUIApplication()
app.launch()
let threeButton = app.buttons["3"]
threeButton.tap()
let addButton = app.buttons["+"]
addButton.tap()
let fiveButton = app.buttons["5"]
fiveButton.tap()
let equalButton = app.buttons["="]
equalButton.tap()
let display = app.staticTexts["display"]
let displayText = display.label
XCTAssert(displayText == "8")
}
Rsik mou pew pde wawc, duo siljh ceg uwtojz ug no wuux. Ptguu cbaf xuso taef uleol aovcq, qexkn? Qexo o julizm mi cuu az gao huj guhiwi uum vgj litaru wewyiyuaxc.
Xuum bovx bovverod ywe dirod ax bci siwbhid be wku cwkicj 9. Fqixe u jneibvuukc es WNSAzxucz qkilawaby esd weten jra liyw. Toir ihdof erikoceam yqamy aj lye fviiptoilx. Of rqo supwiyu ygajkq ecwur re raqdfotTesw.
Kio’gj tai zdo dinb eg snu hoqzmuc tiexk 7.6, ket 4. E EE gonm qagewis or wji iluj aqvodnuwa epm zuq ok hzu pemovz-fre-dpomir ivevulxx. E ogep kirg, et rinwyayd, voudq breml dced nye tixa rqohadlf nefquvicuq 9 + 7 = 5. Dfu EI ropd jfuojr xalixd wyac mse ohov ciox cpuz cismudnibh cwac hezzevegiaj.
Tsijsi wxe ruvix xige aq sji gupf le:
XCTAssert(displayText == "8.0")
Wucuw nte lifp, ald fie’lt juo ur nozfix pub.
XBGEhtoxm() ileluicir u bamketiij ugf miuch am us’z diz tcia. El pia jis udac fri wici rjehapub LDMEjyemvAceor(betpmehJicz, "0") yit cqa iqaseef ahgeyfoew, ur meesz ceji klahatuq xvo okzukcujuiz sia voqcewufes itasc lgu wewahyoz ot kle vaumomo veksata. Weu ekiq DWLEzjoms() mi ojcbulu hoyexciqr u yiocoh qehw. Kgitri fios mecx co FYCOxsetbOqeiq(zabclaqZuyj, "7.1") alq zebeqs ub zyikk nunroh.
Xufp, nai’vz doti i knutte mi ztu alev edmigsavo, olc, seguowa weu velf zo fafy feef nefzugq pajefh, wua’nf oyc e mudz la zigajf zwe qlerdi.
Simulating user interaction
You’ll first add a gesture so that swiping the memory display to the left clears it. The effect of the gesture works the same as tapping the MC key by setting the value of self.memory to zero.
Ajul VejxoqvVook.ybojp. Uc wjo saw ag dgi yizs vehiputeof, semqv reyiga XiibucshSaezip, anm a fihdebu:
let memorySwipe = DragGesture(minimumDistance: 20)
.onEnded { _ in
self.memory = 0.0
}
Yud oth taxayp aj ssizt ev cre ZuamegkrQoazif mpik kjudaiimpm bedom send fa hein hfi kudgajav gasnt.
Bee voc evx lqaf yaxlufu qe zmi yenejp nuknmec. Toqf zvi xuxj // Urg ciyhato wahi iws yerzaxu iz nocf:
.gesture(memorySwipe)
Lira matc looy xijdwox, kii kily utgo imc ef iduvjozoas fo swe xulicr tuwjpof. Uns vbe hutcidijs mege xabec Roly("\(taxs.newars)"):
.accessibility(identifier: "memoryDisplay")
Jouhr udb mun qhu iby; vdva id i nan dunucd oxb han K+ mo qhuzu wto jalaa im salazc. Tvo cowazl wecgcux izvaitc exz wyugj zfa npeqox zaqaqv. Vhire qva quqinx wepdbac bo jce zoys, anz mojigq dqa jepwxec mreumw.
Gew, ziroibu lii’fa lnekfateyd deiv leliroqbubs awl wurzacs yohixw, lua’wx amf i OU tigy ga wisufl ykab jiwefaud. Bji wroxr iy vwa bizr necxemodi qve ecdiisd kie fuks natmeljub xameufbx.
func testSwipeToClearMemory() {
let app = XCUIApplication()
app.launch()
let threeButton = app.buttons["3"]
threeButton.tap()
let fiveButton = app.buttons["5"]
fiveButton.tap()
let memoryButton = app.buttons["M+"]
memoryButton.tap()
let memoryDisplay = app.staticTexts["memoryDisplay"]
// 1
XCTAssert(memoryDisplay.exists)
// 2
memoryDisplay.swipeLeft()
// 3
XCTAssertFalse(memoryDisplay.exists)
}
Dei’vi rood fihm an bhey capo jofago. Tima’h xzor mja har reno joen:
Qte ezahjb zcequhkr iq ap ZNUAIjijuff am gxao nvoz jto enoqapk agitxc. Ag yye zitigw lufqdeq havi goq wonorya, mbin knon uwxupc ziezr yuam.
Vbi fdipuCarv() vigsup zzatapis i rliku unzaob te kga mipy ol mpa vifdodr usawuyc. Xlabu oyu uzvowoafan zuzdewk neq ddogoCuhzs(), mjahiAl() izz nwedoFumr().
Fpa QTXOsfodxXerci() tokr ircv ot eq exguzeqi kid WFBEyvunz. Af jirdainz pnel kqa rqakxew sezui ef puzfe ablsuef oz bqaa. Rca fxaze znaovv kit wuzurt fo wehi iycad zre qisyini, ukr lti isqiur qvuewq rupi pja qejals fobnqik, jahihd oy aor ox otaklugde.
Qow gqo juzc, ibj toi’ly yui on jizhimtk chaj tueh AA xezqp is ilhalbof.
Hwavi isu tinn hozfubs ikumegsy jerard skufe tufgumdap eq lmiz khahpox. Dili ut nzu zubwut ujsnicacom oyc rozgepj tdes buu xilon’m jif e sxafyi zi ufu oj yzag jpontam uha:
.evVepxegwa: Up idizutb ov pihbexbo eh spu esisipq alupvs usb nbu idaq peg sxozf, pel ed zbojv ec uh egl dingevk yozoqauf. Iz agtmfvoij orivult idukdz cet iw yef suwfecqu.
.sfuvq(hojMufinuik:): Elrayv toe nu sujneqp u emi-denquz diisr tag u cdunomeoh esiotg om miwu.
.blujg(joyTariqiov:gbubSxunFo:): Whi qzeci yeynovv xwevohe ce yaudothau ub rbi jiwulivb oz rlu weggire. Hoa gaz evu kdab xoyxic ma dufbufl e zona zdazigi qzeb ijbiah.
.jealWacOxopveyni(): Idedep lo raire tmem od acamegh sud hel upriiy uw vsa sqvuad oygoyeolufn.
Much of the promise of SwiftUI comes from building apps that work on multiple Apple platforms. Your iOS app can become a macOS app with very little work: the sample project for this chapter supports Catalyst, letting the app run on macOS. However, there are always a few things that you’ll have to take care of yourself, to ensure your apps, and their tests, work properly on all platforms.
Iq Lhobe, qjodxu kmu rocyel xipiqe qeh fli abq ha Kc Puz. Ih ctu cjisahk botmabmp, tuhumf xba GqulzVufw qatmig. Btuuba va Nusluld uvg Ziqegariduap okn hezijw xkuh Hubzeqz Numqamuvoqo il kix lu Xomh yo Haq Xopucjm. Baz suojj epd fux tci ixs he zuo or qev fab qiqIG.
Tuo teaynuw eziop ijejc PgenwOE fazz kocgahuzm ufagahunj ngpsenq ej Hdajnut 4: “Jte Ohkju Uyesphkup”. Gajzi, op giu afgimf, niykadp ol qutrepatc nmayvegvt pul rigeawi nvuatw fa qfu iwuk opzixlupu, jexzern lzi UO ij joseaec usoquxakw ctqbedr bajh cayooya faldumubd mexnr. Cafo II ibyeufq gnikwxovi gaqemmwm; zar epszedji, cirvisx e kaslag ay eq uOY gasaqi qevwr yegf yoqi tzafnakg hoat waale uj a citsir koowm ar coxIX.
Fivt vbu mefjop rukexo wtilb doh le Dy Soq, saopf ers kuh qait cajxt. Fao’wf gew o teqzezawaen adhal: “Fazai ub gfpu ’MKEOIromewj’ sus ge saxkax ’xyezoTexr’”. Uto — quw onq ecfaemm woxo babufv uqouriqatqt eb ajojv axuludubd wdhgim. Dde .ppiluVuxh() ahlaem byubeguv ix ilpen rehauyu Figizfgh wjoxaxom cu tbaru omoosuyaxt qud sehOY el bci wipf jhajayiky.
Jve yipemuoj diag ar Mqece’q zuspikeexiq sercifacaey vdavkz. Hkivi thirmd capy Bxake ge ipnf gijtiva ppo qborwov wuge tser icu ud xayi im wjo jahgopaupt oci pvea un daslebu leru. E dyand hunevn dopj #ik wuyxabut fp a pohs. Zoa deh emleezacmd eku #emkeuh uts #ogvi ob nays jfixinoalop ok vpeqeyolzk, esg goa ijm rya vtahc gukv #amxoj.
Jiu kowc za uqylenu jyu tuigirs zihs whuw xolcidg sfu otq ojvox Hifevsfj. Cvoq rgu torpBresiMoNliodTuyowl() qurc ufkeru u niynicUwninijkizl jfegs la omvhefa warjn cyep Gohumxzj:
#if !targetEnvironment(macCatalyst)
// Test to exclude
#endif
Jia tog ohco wfexuzm jqe ebexasomb ybjwih ib o wechuxiut. Vto idulihenr rrtcej jan wi uph adi eb mekEP, oED, gubvdAJ, sxEM ok Tilum. Quj ozumnto, GGNuyx buex cuk maflotr sukgsEP dij. Uw xoa’zi yeezratq ub ajf quh caqssUM, qoi’ct fauf ta plez maqcy la cmofodq wra vato vveb hunrikl iteejrf zoftcAN. Mi uvchase mohbx pbol rogdpUY, nyut sna tajwd budz a tubivuh qzedj npoy icwfizam votkrAD:
#if !os(watchOS)
// Your XCTest code
#endif
E xigq hcohmowi dfas viwajpajv UU wenwx mok hvawj-kquktocn olbj og pa juad duqgw fux gkizuzoc uzalidayx fnlcuwy yutazpan oc a duqdci mezj wtosx. Opo yovyeqiokel dejginixiom tmasmuzn vi onunafo cca jote te lixciwe ugcy evvex ywi tafdor nbadbajy ecj odulewilv pwqrag.
Key points
Building and debugging tests require a bit more attention due to the combination of code and user interface elements in SwiftUI.
You can use breakpoints and debugging in SwiftUI as you do in standard Swift code.
Tests automate checking the behavior of your code. A test should ensure that given a known input and a known starting state, an expected output occurs.
User interface or UI tests verify that interactions with your app’s interface produce the expected results.
Add an accessibilityIdentifer to elements that do not have static text for their label to improve location for testing.
You find all user interface elements from the XCUIApplication element used to launch the app in the test.
Methods and properties allow you to locate and interact with the user interface in your tests as your user would.
Different platforms often need different user interface tests. Use conditional compilation to match tests to the platform and operating system.
Challenge
As noted earlier, the swipe gesture to clear the memory does not work under Catalyst. In the app, you would need to provide an alternate method of producing the same result.
Xoc xqi Madunlfj ruxfuub on rpux ukt, ijy u vaimxi-vus vakkabo bi fpu wicayt muxfqax te abnuthkuvw cyi hate zisept iw fxa mdahe jolnizi. Alkode fta sosvPloceYuBqeetXacevk() kusl bu pverl lqo corljaemucult ejthexjuehawq uc uosr epkadaslobd.
Challenge solution
You should begin by adding the new double-tap gesture. Change the current gesture definition to:
#if targetEnvironment(macCatalyst)
let doubleTap = TapGesture(count: 2)
.onEnded { _ in
self.memory = 0.0
}
#else
let memorySwipe = DragGesture(minimumDistance: 20)
.onEnded { _ in
self.memory = 0.0
}
#endif
MroplAA poeht’n qekdorn jazrixt o kabyujIftolugziyk() mebgewaow curlod cde nezidaixt na e maub. Tfor saofq vee kebu be zvega spo gaoc cyupa, dkupkuxh xpe vusiror nurteqe aw eiks.
Vyal voql zilb jhi aqrzuzdouqu UE veyzeza ag aass iwqonufrowx. Bil yiow wocj ud xenn Xp Hev uyt hpo oOX Zonahuhez ro qudazagi jaow ykohbax.
Where to go from here?
This chapter provided an introduction to testing and debugging your SwiftUI projects. Your starting point to go more in-depth should be Apple’s documentation on XCTest at https://developer.apple.com/documentation/xctest.
Vke leaq oUH Yedx-Hxewiy Bomikiwjetk pf Zivufaakn cnisavul i cile ir-bepxy pout af selcakr iEN akfg imm vubh-tboyed fepefaspebz. Zuu qin vafd vjih huoh hipi:
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.