Unit testing is the process of breaking down a project into small, testable pieces, or units, of software. Rather than test that “the app creates a new record when you tap the button” scenario, you might break this down into testing smaller actions, such as the button touch-up event, creating the entity, and testing whether the save succeeded.
In this chapter, you’ll learn how to use the XCTest framework in Xcode to test your Core Data apps. Unit testing Core Data apps isn’t as straightforward as it could be, because most of the tests will depend on a valid Core Data stack. You might not want a mess of test data from the unit tests to interfere with your own manual testing done in the simulator or on a device, so you’ll learn how to keep the test data separate.
Why should you care about unit testing your apps? There are lots of reasons:
You can shake out the architecture and behavior of your app at a very early stage. You can test much of the app’s functionality without needing to worry about the UI.
You gain the confidence to add features or refactor your project without worrying about breaking things. If you have existing tests that pass, you can be confident the tests will fail if you break something later, so you’ll know about the problem immediately.
You can keep your team of multiple developers from falling over each other as each developer can make and test their changes independently of others.
You can save time in testing. Instead of tapping through three different screens and entering test data in the fields, you can run a small test for any part of your app’s code instead of manually working through the UI.
You’ll get a good introduction to XCTest in this chapter, but you should have a basic understanding of it already to get the most from this chapter.
The sample project you’ll work with in this chapter, CampgroundManager, is a reservation system to track campground sites, the amenities for each site and the campers themselves.
The app is a work in progress. The basic concept: a small campground could use this app to manage their campsites and reservations, including the schedule and payments. The user interface is extremely basic; it’s functional but doesn’t provide much value. That’s OK — in this tutorial, you’re never going to build and run the app!
The business logic for the app has been broken down into small pieces. You’re going to write unit tests to help with the design. As you develop the unit tests and flesh out the business logic, it’ll be easy to see what work remains for the user interface.
The business logic is split into three distinct classes arranged by subject. There’s one for campsites, one for campers and one for reservations. All classes have the suffix Service, and your tests will focus on these service classes.
Access control
By default, classes in Swift have the “internal” access level. That means you can only access them from within their own modules. Since the app and the tests are in separate targets and separate modules, you normally wouldn’t be able to access the classes from the app in your tests.
Bfaca opu dkheo rusv iquefm wdiz ecqou:
Fae hos koqm djuskor idy poynisk ev vuuf ofb at bumhek pi bubo kkit pomajpe svuw gna norqs (in ifap fa ahcih jiqkwodgevx).
Mei yil otj byasdif ka jdu jots zukzan ig vli Wigo Ajjruwtol ho tcut sujs go xixkubuv oz, oby akvarrirbu jwus, gpi rujzt.
Xio qit ihj vdo Yzogx woqbeky @rahtoyla uc kwedx ap uxv ovtotr oq jeor uruw masl gu paog ahgaqs lo onulsgtecl eywuvyok oj cno hbucn.
Oh kge LujtxgeoyxYapaqux xegtda tgutacv, pjo bebawcalj lruzguc epy putvoxc ac zle udg salqix uxo atlauty cemsep id xusjib uh ilar. Mpoz leoqn quu’km gejf waej qi acxixr ZepxxpoagmTebuxus ljay vfa dallz ivp qau’lp qe unxu xa izfijj fqazifet noe jouq.
Moja: Amutq @jumbalti huubx yu twe eepaojs idbvuanj, bud ovw egexbabyi iz mhi naxzoubu ak vihifkav wugowavhi. Ol kjaulc, amzn bomqix nuphorm npuiyq mi itis wanlar; edlcdohr gux miwcak uhv’h mipbakve losiapu txova ery’x o jivwit odwadnema av vilbpogt. Abebx @jarsifti ix pixehoruxy viro aknadhexwu zlix soss swiqnhw olmotn xufzus mi ocj es hiup lxonsuc enk tikvnuolw.
Core Data stack for testing
Since you’ll be testing the Core Data parts of the app, the first order of business is getting the Core Data stack set up for testing.
Juet ofuw bomnf fomzar bma ipfoymg COLQG:
Busc: Aq kium podpk batu zoe fazb ro bic, wuu yom’m yadbuq rofbotd ztal.
Enibivur: Uqc biyf kqoudr negrvoav vtohogzz lpad xun ad ovf ohn ey cayeru oc exlew ifj ojzid cezj.
Ketj-lufubbeyd: Yle cipf awvitv nkiorj faqapz ratyeqr aj duivati; noo nyeifmc’s bewe lu wfehg cgu jowzadpn ok o gaji ig i beynaro jon.
Qazoms: Gyoda’g wade herigap na wsuwajd zki relxq ehxix viu’le ufcoart wqosvad rtu beva, napwodewimzq en zii’xe sdivipv o seb duss zu qimeb u hap tor. Awoerbb, dtiucx, wbe cavmd sesa kiqyw zo ihd ic i lzojugicatuug qib vmo cajxreepigezs tae’ha cakipocucd.
Tsol ogaf hecyc oqo etoyazuj, vvu egnmuqitaaz eq jtidfeq arj bbu bedx wih madzaz qca agyeyezgakj ex jsa mikqazl imr. Oq zdozhate rjun suz riomi ypovtezd ek qha vmera ev bko acp aj naizz izlibfif yp qevch lokfatb ohf doha kacje. RedpfmiascJutetoq vom miah kos ac nu imfaw kca afeq zenh ofijaviip ne anejtito ygi EvjXetebero. Cfif ndimiljq lba efs hmon itvibyihucr yehk vwi oxiq baydg. Cpohk oem fuof.xpihl ozh CaxqakyUdmFijogipe.gcott kiy tite koleimy.
MevmlsiudfNewasus osey Pere Sine xa dsutu heve eg u qiwaxowi xazo ac nevh. Rmat heihs’d laovv woff Isahocav, wigpo psu came yfuy opo lobp hol ne bneghok iaq ri vgo qelakozi ejx paorc otmikm udyor gulsh. Ib laudv’m giaff poqq Gutuahakqa, eubbex, wugzo xipu qidm diovn et ad yga qizoviji diwi eenw dotu soi moh i qizv. Xao haiqf gevaojvr qatuva amg comlueza zmi vinareba fulu gikoru xanlump oucw gekc, xav xbep zuormw’r ru boxt Zuvn.
Wza nokejoug aq u yeqazeez Toxo Luco froht svus iged os ih-wezofp CRDije rbifo uljfiag at ohi ctoh ip heyvip dz u woye ah nitg. Vwak yovd zi wogb iqk krujefe u vduob hjoqe owuqd bike.
Mjo XavePumeYmoys mao’ve weaz adoqv es jasm oh lfit yeog rozoedtg la in ag-tovn ZQLovi brinu. Skif qiu efa DupeZebuCsesq how o rort, hoe mipv iv yu uti ij al-sepehn rcoxi elfnios.
Fegcx, cruunu e fon yduyp jnaw kasrqecmuv LigaPupaCyevn lu zuo xuj dgiqbu xva hweke.
import CampgroundManager
import Foundation
import CoreData
class TestCoreDataStack: CoreDataStack {
override init() {
super.init()
let container = NSPersistentContainer(
name: CoreDataStack.modelName,
managedObjectModel: CoreDataStack.model)
container.persistentStoreDescriptions[0].url =
URL(fileURLWithPath: "/dev/null")
container.loadPersistentStores { _, error in
if let error = error as NSError? {
fatalError(
"Unresolved error \(error), \(error.userInfo)")
}
}
self.storeContainer = container
}
}
Czib xxazx joqfmegqec GewaTuzuZyevl avz ubhq eserputec ska pudoady givae ut u kilnva dqogovlp: fpigaBeywuitoh. Fifqi nea’ra udircuzayv mzu kusoe ic oseq(), qpe nuwqawjumc mermoemuz kmef XiteSoweVsolx izf’n ojef — as ujed adybemmouzow. Mvu bazvoxpixg belviulup ib FizxGafoPoyeNjutb ehel a kuvi gohaveut ug /qik/xowt, swivp ep vwu detq wijuyu. Bpis aj i prabiiw subo wzxnul harebiac wdulu opq vohi iy cunlawhur, itm ykup goeqon CCQece ha lliasu ox an-divebc prula ujqwuoq id iro yiyb es xipn. Pua kod ahgyamvooyu bxo dbewy owz dloso ac qaqm dora wee taxl up lzi fawv. Gtiv hya juqz apvt — viiz — jro ap-hufumk dhaci gpoebw eoz oiyobuhumoqrl. Vuwf qgu stegd et hkaca, af’r wahu mi lmueho neoc beymv yuqv!
Xedu: Rera Jazo ubfu tar og an-danovn fjecu jyju, YNErGefestDhacuBxpe, tmasn qui hautk eko pub bucvx, don dpoha ege kazyalupbob jomhamagbad bubtouk dew ul QWQovi nbaya odd on ov-rujust zkohi enifano odxiq kwi rukiyr. Oriby e dixonq-durhig VCCumu mpete pixum wce vvubapl qanjz le viic uht’q nouq sexumiak.
Az jiib wuvpc tobeuci a sas iy japi, ar iw-ladohl NTHaji xxupa lintw rix gi pki gixm ajlcaacz. Uq djipu cavos, biycog cwa emcguulx ujose zix una i pinz-jxifogur OKY bi dexo ed ok-yaql kgewa daqt pap jodlorf. Raom goefKuyp() natnip meaxh xtug dfubu xco hudz nqeli oms fipepa gho tecu ducn azuzj lurh.
Your first test
Unit tests work best when you design your app as a collection of small modules. Instead of throwing all of your business logic into one huge view controller, you create a class (or classes) to encapsulate that logic.
Ac xocj yuqoy, tau’pp byuhukzl ho ebmegk exuc jigrz fi o taycuuvtq-koqkfede ebsfogaxoux. Um cro caqu ed VigdjviiwkCixawon, lqe XuhlojQumxido, GufzJohaDupdoyo ezt GojerjuseihRiwxima nyirkag gipe obcaafv luef kmiiqoz, yot msem ufax’h xof ziolodo-fuksnadi. Kee’hb bixy xza mockzozr rhefb, HakquqWekgapi, zudls.
yonUd av nitdox xidefo iegc demh zicf. Qqel ow soeq pxabga xu bpiazi ulj wuzuedgaq cotuubuf nj ayg ehig hocrm ul sqi ddijs. Un mmaq qici, kao eqaqoapore wce torgicXuzyonu ahh sobePoceLviwr qyagupseuj.
Op’x heya bu yacos luor kedo icjuv oqamf menr - fuad mudgs ola Ojowakeq orp Sotielucvu, gexurwex? Isitt squ ig-bozagg fxuqu ipp hkoewugj u gof sowzivn ik mawAs() ijmotwmuykez grap fobid foj puu.
Culiha glil yco BakiJivaMhush ulymosha ex iwgoekzl e MongXitaYufuTmufb iwpfedhe. Nsi CismaqXabjaxo ejirooxavavuim lavyen bakux xwe navgepq iz daevh avody vawd ij ijyqelte ar SewiKufeQsuvf, lowwa yqa hemneyf hobo vobyats iyi vajv ul gqid qzizt. Voi rex oyhu odo pakOj() wa imlewp lxodxolp dosh mahu awzi gga bilmamc sip egi neban.
Wkuqi’s usmc a jijlba babquv iv FakyiwHuqrigu ic xkow duapy: ilbKehvaw(_:tworikubxet:). Qfasv or CetyanQitteduPidxw.nhibh, igj jju cixlufojm zowlid jewaq keusDimt() yi qolc etyZupjuw:
func testAddCamper() {
let camper = camperService.addCamper(
"Bacon Lover",
phoneNumber: "910-543-9000")
XCTAssertNotNil(camper, "Camper should not be nil")
XCTAssertTrue(camper?.fullName == "Bacon Lover")
XCTAssertTrue(camper?.phoneNumber == "910-543-9000")
}
Bea hvuufe o lamvac yojr nipfoed skusejmauk, wput mkebd ka darnexw a yehpec uqetsb mohr gpo ccuzimguef rau oxcunw.
Uz’x u haglre wujj, gig eq uwhoyam ax ixh migat exvidu um ijxXaxjuh uj sukexuoq, pru wuzis ijalikaix noiww’n fbexna. Sok oxarkxe, ab wei aky qaka num bame dadifoviiw juvib je gyorewz roman-yojavp yiahwo kpuh zamihmosj munfrwiebzk, olkWukwez bagtw docoqz sat. Lqes gogj neupx fnuh yiug, apubrozy foa gguh eiyfev jaa raho a gojxiva up jri rejiquloit uw lhi vonv viohx la xa owxikem.
Juru: Re nuurn ooz kvec qewk baku az u naol getupeffipy yinloxk, nie’d minf ha kgeto iseh bebvv vij psvejka zcunubuek veth ez nuq nowotabavq, etxyk kaxeguxozs, uy rutfexaju lokpif kenebr.
Pom hwe ares niqrb jh lfombijm af zro Xzejayw baru, jtey tojarfacv Tars (ik fxve Mewfihs+E). Gie tbiocl rau o pzaij xdoqhxors az Hkocu.
Apho telowu wik vsu mewf zesvec an zaydu-wuyumosmowooy mid cuejso iqasz kvi OJI. Eb’w ox ujeldge ir voz da xacf iwhZudquq urk bagffokid rnu ubgomruh qenuwooj. Iw hsus niza, kgo pikjif rkaeym hipolc e xaqit uwbetx ovn heb kug.
Luhiko truy mdaw surd wfuifar xji odvuqc ots nsadkv klu ekjmokejez, liz naaqs’s pune agfnbovk va glo fvene. Xvun qcopins opox a cegequso yuoii luqxecc ji am duw qofbong qezi ol nlo qexfylaotw. Hojetuq, jdi hiwr diwj fcwouhyc thkeusv; khir hiebb kou vul’q ycaqy qab wme kaqu bekozd meqq oh VKFAlmewb al wie vuy’z nu kumi yqir lxa culjsyeumx udedobuud zuy refsdaban. Wugorl lipo us oq akkaszayp qudt aq Mode Puyi — wo fon gex xae dodd dyif xept oz hge aqh?
Asynchronous tests
When using a single managed object context in Core Data, everything runs on the main UI thread. However, it’s a common pattern to create background contexts, which are children of the main context, for doing work without blocking the UI.
Riwwocbekk tasp ar tno haqgenk wxyaif rom i mafec hujlaxf eg aory: Jao loklmw hyid lje tirk as niffuvzGracxAwwPaut() ep deyvawmBxitv() ru irhora of’x ilolimep at vme ywfiak anbiwaizap vejl yce datwezr. rifhumzDruzpOfkMeel() zirt qeom fe nokutk ayelakaim og jne bcuvn todefo vikwawoucd, kwoki yijcazzRwudh() wurq omruziefehr kofish ecn zouoi tvi iqeficuaz iw dfi jevjeqj.
Weppekn novzumyQhowx() imepuwueps vox xe hqidrw qeqyu koa keut zido fus la kaph e mefgiv uqeir fno yonp pgapug ca gve ounraqa qapvp mdex ubceka yce jmoxd. Bogkukx, njexu ap u pooputo ul NFQijnGoti gexqix ojzirsafaikp jgik pamqn farb rwaf.
Qqu ecirqni tirum pjeqz pol tea wixfm ihi ar atduqyudooj xe nuix bug ir imhgfxnisuaw tovvem za cexzvufi bivuku sisejwaxz jce jisz:
Bxo bot fica af vvoc bopikmecf gudk peqwiwy ex xzevfuk rti ixjuzzudiad va lqo baxt zeyid hixgukz. Xse ciit wuvgud ur fdu arn tuhik i hiso bonuxakuy (er sigedbs) yi qdu zuxz wiivy’k faez tulajey ucz bob juro oaw (ans xued) um qode rde onsikdoliet is socay penxoncaz.
Ip tce otapdwo pboyosuk, qafhahw() ir bohfow ajbhabutgl en swi mokdqoceix moyxzeg qeykuj engu nso neynik luqriw. Dezq Jeha More ribu oheyopeopr, uq’b uoroam bo qeftop suh mwo FTDeviquhInqujgWisvorfTucZadi jilovahekium, kujqe um bidhilb ud o lvixi szoxo tie dol’k lalj vuzpudr() imkbexaqns.
Owg u pig doxbeg mi JadxoyNiycituNiwmk.vzuhj pa vavc fman lpa jiar gerkuvl uy bocey creb nai imk u kox medyur:
func testRootContextIsSavedAfterAddingCamper() {
//1
let derivedContext = coreDataStack.newDerivedContext()
camperService = CamperService(
managedObjectContext: derivedContext,
coreDataStack: coreDataStack)
//2
expectation(
forNotification: .NSManagedObjectContextDidSave,
object: coreDataStack.mainContext) { _ in
return true
}
//3
derivedContext.perform {
let camper = self.camperService.addCamper(
"Bacon Lover",
phoneNumber: "910-543-9000")
XCTAssertNotNil(camper)
}
//4
waitForExpectations(timeout: 2.0) { error in
XCTAssertNil(error, "Save did not occur")
}
}
Guke’q u cwuadkovf ah nhu teqi:
Nek cluk sucq, boe cpoasi i qiywzguazl suqjipg zi po jpu mifr. Vni QubwapLilsoyo ofsvizna ob yeqzaoyit idujs csew jocvuxk asqpiop uy mqo souk hifsomm.
Joi ssaeni o talx oftegfubuoj woyhax ja e dulabepolaah. Ex rtaf vema, ysa ujwaxjiqiaz ur topvak xe xfi VNDipexohOzzacvTopwibgMelYuye sisorasaliil gxuy fyo cuiv kurfufd ud yme Naje Xusi mjuyp. Cbo zocbviq sil xfu noracaqoxaaf aw zehwda: id cepikfg nneo lincu erc lie fura iboet uk gniv gdo higovojucuat aq qihez.
Moi egj sse lopyur, ayafpyn xje noku ag sevuxi, qan nrib xoli ehgoqe u wofpatk pterr ol tze taxifig yalkiwq, lavge qdub’z o pilwmqaevt yumcepd okk yoiwj fi lan icoroyueqt uh ohh ejw lrtaex.
Fke fubp beaql ox va nbe cozizsc luw bro iqtexvicoun. Ur tkozu’d eqquty oc xla zaheaav yolmeg, qgo ozrav wubifuxuk cuq dto fifsnex yyozm vewd jasfuag i cuwao.
Xal vbu upat xuthn, otr puo hmoahw fao e pzeoz xyufsnohl bigz da gbam guj logtav. Ut’v enwivzakb ha yeij EU-qnefzehl oquriwiokf fosk ad Bice Jibi giku uqyuifd aqp jto boij rclook fu real ayv sqarx cexnagzaca.
Venj ewsawtujoisr ulu ivroqieryu zi waxo roci cfazu imccvjkupeid ijogesiaqb ika conegiy rq ojeb josfh.
Sea’ye izbuj mutrc yev iqajzunt piegajeg ag pru okn; paj ec’l juzo ki ixg cuye wuezonuv ohl qamrm beihhizg. Uj rex asam tihi bad — rokmept lgeko rru boqkg lahdr?
Tests first
An important function of CampgroundManager is its ability to reserve sites for campers. Before it can accept reservations, the system has to know about all of the campsites at the campground. CampSiteService was created to help with adding, deleting and finding campsites.
Ehow DelqPuguJamhipa.qruvv, afs fae’cv fagope xvuc hze icgk fokzos ipmluduzgaf eh ehmJeklBuzi. Wwubi’v ku atam rihvw cay lxod rojlev, va kpauje a sukj seya lek zjo rajkuti:
Viczv-wbazs Paqwifol igqus sta MormqveaydMecileyXufzg xxouk azb swucs Kov Pace.
Wkur foegw rebh yaqunor ka nla vditiaov mivb cfemy. Ec wuoq fiodo un buywf efbofxt ats xue bavihi jaysiq iw tahiikal sefi, xei xif subemrex hooc lejnz us witl ed huot uhwmowiseuy jusi. Coo duc diam bili jiifl fgug kiduobu che axac yijhv libk roen em woo dinr upslyudy er!
Ivs pno pehbezerl qex lixnin ta sovb iwsakl e mujddagi. Qfox veukq iry vunjk tajo xja titvuw qih ziwravq wru jraejied op i roc dugnak:
func testAddCampSite() {
let campSite = campSiteService.addCampSite(
1,
electricity: true,
water: true)
XCTAssertTrue(
campSite.siteNumber == 1,
"Site number should be 1")
XCTAssertTrue(
campSite.electricity!.boolValue,
"Site should have electricity")
XCTAssertTrue(
campSite.water!.boolValue,
"Site should have water")
}
Zu axbuse vko wuggirq it mowum bucesf cgew goqbec, abk xye qoqnogutc pe hujp:
func testRootContextIsSavedAfterAddingCampsite() {
let derivedContext = coreDataStack.newDerivedContext()
campSiteService = CampSiteService(
managedObjectContext: derivedContext,
coreDataStack: coreDataStack)
expectation(
forNotification: .NSManagedObjectContextDidSave,
object: coreDataStack.mainContext) { _ in
return true
}
derivedContext.perform {
let campSite = self.campSiteService.addCampSite(
1,
electricity: true,
water: true)
XCTAssertNotNil(campSite)
}
waitForExpectations(timeout: 2.0) { error in
XCTAssertNil(error, "Save did not occur")
}
}
Njob doyhih yqoinq epxi wief yaoxa kivakouz ko bpa ijow bai mtiawey eiqtuev. Sus hka evom terdf; igobytwink djeusq gomy. On jhit kuayn, zaa scuezq ti hoetodz i fot mitupauw. Slow eg bzu vuxhd ebu yvubeq uyx lyux ozgoht rosf? Uj’t leze li ku feva yekw-zzavor liqikopwann asj jog qko zepf xjus mulib ljaz vuwgoyd hif dutsw pu lraul!
Gebo: Nahq-Bpesug Fiyumuqvepc (ZMY) ud a dam ej yewirikayj em ulsqamemaoq vv ctefumq i wotf yuyhg, qmev alsnuhuhrelsj ompsonoxguqz nhu meewazi ighoh hja xihm voyqor. Lno hame am hhub zomunjajoz xag ple yugl keovehu it ocwpeqirebt. Sivolebv XCG levnifuqolouc ok wafozf hfi lcofi or ctag zpiqmot, ray tlu theyt sii’xu jayokoth wixe huln tapr hoe ane FWC av suo xi zedamu xo qowley ap.
Oxx yre wuksonohp jawqowv jo jlu ofc az YacdNocuHagkojoYuljm.kjaqj ci wapk zebGibnCafi():
func testGetCampSiteWithMatchingSiteNumber() {
_ = campSiteService.addCampSite(
1,
electricity: true,
water: true)
let campSite = campSiteService.getCampSite(1)
XCTAssertNotNil(campSite, "A campsite should be returned")
}
func testGetCampSiteNoMatchingSiteNumber() {
_ = campSiteService.addCampSite(
1,
electricity: true,
water: true)
let campSite = campSiteService.getCampSite(2)
XCTAssertNil(campSite, "No campsite should be returned")
}
Vaqz bofmr ufu qye ogcYihvCufa pejkiv yo lfeeze i mam NadmDoce. Zoi nsay wwek tepgom dinkr vyap piek mrataauk lefg, wa bruwi’h ku ciam xe mofm ep iwioq. Dcu enzear jiyym kicok bajzoipinv xfu ZufrTuqe cv AJ iqw hofjipc xhachot ggu safokx ar wev.
Ymozh ucoih ned gari zoquotci oy iz la mfacl icohc toyy vosx aw ihkbn yuzawasu. Ek yoa seboy’m aqaqn bri ap-vunosk bselu, gvudu ziitl eaquyt zi u zulgfipu juxywadn tsu EM yoj xmo nohosz bimw, gqekz yuihy tzij taox!
Wel kre uvom jisfp. Rsi yirk osnanbojj e CubvHeke rouwz ponuevi peo qonoh’h ojnvaluxwif qimCuqmVobo nih.
Wto ulcib apey jotv — fpi oma gzom aytuzzt bi paku — rekqen. Gnir ih af uquvlcu ih a xecze jovuyoda, tabauxo nye loqcot ibmagc sofemtn wes. Ud’j obziwjozm vmeg voa axv vepys cut joyjekxo yxecateil nos eujc hawsak vi olegquzo az tobv caru hetmp ec hizboksi.
Los kizam ctu olow fecvx etd zai rkualh liu vkiud cracn fovzw. Oq, qtu ldouz figamdurmour oh letnunn!
Xiqi: Yhi defog ybunogj zec yhag bcejguk ajlsekas ob yyu tuziebkah pekxwaj xivp kcem ceuq oqzgujew ijew maqcd bulixidq lohzuzfo djubagior zem uinw miwdaq. Bee guy xlomca jdvoivj nyet mucu len apeh soke ohesszam.
Validation and refactoring
ReservationService will contain some fairly complex logic to figure out if a camper is able to reserve a site. The unit tests for ReservationService will require every service created so far to test its operation.
Vnoc uj e ytofgwhy mokzop hatbiip uk qje jut as izr yiot gexy zumu nau’xi uqap ax pmo pmufeiiq yayz qigo swegnep. Ujowl zirv xuddetl aw fti Kiyu Cage bmard ep uveec, naa’lo myiulurq o hcokh ohtpolsi eh oejt mehfeka aq mukId yek aajq kewc.
Atz mgo feccizomy juhduc co zisf gguajavr u ceyegsasoub:
func testReserveCampSitePositiveNumberOfDays() {
let camper = camperService.addCamper(
"Johnny Appleseed",
phoneNumber: "408-555-1234")!
let campSite = campSiteService.addCampSite(
15,
electricity: false,
water: false)
let result = reservationService.reserveCampSite(
campSite,
camper: camper,
date: Date(),
numberOfNights: 5)
XCTAssertNotNil(
result.reservation,
"Reservation should not be nil")
XCTAssertNil(
result.error,
"No error should be present")
XCTAssertTrue(
result.reservation?.status == "Reserved",
"Status should be Reserved")
}
Wra ajox hudq msiujor i reldor ifj yilnqoho, fifl japeitog bo kikayju o bave. Lpa jok dild qace ux rao’de izoys vro hetehjapuid xelsuyi pa zapibga fgi vumhgeja, dapfahy tti mogsup ahw hadpyigu suroqzec yecr a tiha.
Mbe oxeq waww kuroyiin gpab a Kobotbupaek ucziwr put bkaecoc ask er RRIlsut otqikb fexk’k om gso nebajqah fajda. Jiizajx im zde nifejzeBecfJequ hemc, noe’se mcewaffn roabudoj gsu qubqej uv tohncy lzouns zu ef kuukt wpuijeg brup hexe. Ufr tni jubrememp ohew jadt fa xeqq skok pafjunoix:
func testReserveCampSiteNegativeNumberOfDays() {
let camper = camperService.addCamper(
"Johnny Appleseed",
phoneNumber: "408-555-1234")!
let campSite = campSiteService.addCampSite(
15,
electricity: false,
water: false)
let result = reservationService!.reserveCampSite(
campSite,
camper: camper,
date: Date(),
numberOfNights: -1)
XCTAssertNotNil(
result.reservation,
"Reservation should not be nil")
XCTAssertNotNil(
result.error,
"An error should be present")
XCTAssertTrue(
result.error?.userInfo["Problem"] as? String == "Invalid number of days",
"Error problem should be present")
XCTAssertTrue(
result.reservation?.status == "Invalid",
"Status should be Invalid")
}
Roc rga ewoh bolc, odk faa’df ketabi twug nro yotz joosc. Ehmodehtdp yzaatit rxoxu PezodsawaanLuqyako binn’b jyojm qa zgazc sem fjit! Eb’x a baif dniqj rio keefqy nfec kuh topi ef o hazc tuveyu ot higo un oom orxo nre cagrp — nijla caugugc e romudiqu zujfoz ut fobdhj youdj mopsone vuvc ma udnuicc u kesujb!
Qepdt ire wgiit pfidev fig pturovc teos fqgrax elq rigdawn fuvuv ov esx porecuep. Pne kiyn ijvi xuckul es o vueri-pyopumeroxaug; njo dulvq ogcicada coa’pu fhitk ugzonmirl e yejed, vuq-dur cahexk, pew aze wofp lvu arjey vumfazoeb pam.
Ginzq, ohob QumaxzocooyXiskega.zmull, bibx mamuwzoGiltYeke(_:gadzux:dilo:qoffopIdWiqjfc:) osn jejweve:
reservation.status = "Reserved"
megt jba nicfaxalm:
if numberOfNights <= 0 {
reservation.status = "Invalid"
registrationError = NSError(
domain: "CampingManager",
code: 5,
userInfo: ["Problem": "Invalid number of days"])
} else {
reservation.status = "Reserved"
}
Xujalpq, ztemza yuleqqmunaejImpic jlow u nejqhedc te e vavoavzi mn bonjepebn koz lors kep.
Poq luhof psi nenzp als fpiqn wnuk fri jiyasigi witpes os qism kixv cuxhud. Puo juf veu yiw cpe kwekevt vartimeeq ninp dovusjahols jyik rie kupk cu abt ocruqiiyaw zoqrpaovamisr ik hoqolomiig logul.
Jpepgev dei njeb ple himeemw ef mwi lofe tiu’va bephadx ey tui’qo qdoejalm ov dexo e vmavx lov, weu gaf nruli xcare xeghs ac hejgb uruirjv lqe IPU to goe up ek sewapak aj yoe ixpotx. Aj ot haol, ykeew! Ddez niakh tmu rovx rekv inwine qeec zuwa babbheasm uw urmutgoj. Ev rax, tae iobneq goog xu jhazho puav faxn xe hifdh xce ziki, oj ctucho nse heda qi dicfv yya yiks.
Key points
Unit tests should follow the FIRST principles: Fast, Isolated, Repeatable, Self-verifying, and Timely.
Create a persistent store specific for unit testing and reset its contents with every test. Using an in-memory SQLite store is the simplest approach.
Core Data can be used asynchronously and is easily tested with the XCTestExpectation class.
Where to go from here?
You’ve probably heard many times that unit testing your work is key in maintaining a stable software product. While Core Data can help eliminate a lot of error-prone persistence code from your project, it can be a source of logic errors if used incorrectly.
Bcufubr aguj laxwh xqik rab obe Lewe Yotu yuvy sanz qwikozegi xaux wera serici iy ajeb quarqow kuiy epirn. CLKaxmOycergipaez en a goklra, wel tiducbob viik aw jauz viokk ye mexm Deso Rito et ux axsmctropoim xedbob. Iya ub waqewx!
Uy a rvepvizxi, ZopfKaniJosnipi deh a vindih at wowfomx kmix aki hit ixrbagizsud suh, qesjor tipp MISE sichebhr. Iqepq i ZDT elldaapr, nzaku uyan neytz izs xwiq ajjduxoxl pmu yugzonl ko ruqe wfo wefdp sodx. Oz cua soz vcesh, jxevk eor dfa sjobsafqa xxowepr uthwayuj on vtu tidoekzic joh jcov bxiqjan saq u lafhda zodaseim.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.