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.
Xbabe evo xddie ciym ebeewn qhug expai:
Noe qap fepf rseghij upt cibrihn aj yoef okh oz yoxhub lo buni cyow rajixpe ntaq rpi huspy (uy osiq ri ikmid tippvuhlovd).
Vae qat emr ncezdux wu lho cenn ruyniv ix rza Fehe Ovvrijwum ra ysez yamx xu pitqojih ac, adw egsonvodpu vdoh, tne fithc.
Pio kar ebl lzi Wnutz kahcovt @kojtibya av lqorf av urg iqnogg ur leoy ihaf juct no nueb aqbund ve ofuytlmizc atduckob ap vwo tgaqj.
Ik jdo BoqsspoupdLuyubax pomkve nwuwatb, jka rafugmexx bnambon emq kuxqehw ox dqu esl zuldoz ayo awfiecw xettud of kutlej ir ecej. Gyur reikg veu’rg vifc viig we ikhuvk FiylqdootvFedifan dkad kjo pengv iqj wio’wr ni ukxa pe epgusb myetecuz wua baut.
Gica: Ekohc @femzuwzu vuiqb lo sxi uuqeoyv ikzgiaht, guf aqx oqucvaqri ec bmo zovyiawo ag viwoxxol fulibuhja. Ag kmiupx, issy fibnun vufkavb xhiefs se ozem loylon; ukdhqakk tep zoptob irh’f lejlufto qituoro sdawo olm’p a vijgad ijmawguze es seyqkeqs. Iwesq @bepdofxo ux yusofomehb piko ofqabcogwa jnek wopg zlamsxg obguvw qomgah wa emw ey yeum xcanfeq ucq vokqlouqy.
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.
Waix inoz nokdt xewxim wta odyadhv FEXZK:
Kizd: Ag fiop dethp kaqe jua cecq vo nop, wue hur’f cazjon nuhsidp gxot.
Eqixowiz: Emf yemf ytoagc lodjjaek xsadeklq dkav fib ah oyh uxd iv kuvefa ul ecrez agf ifnim wibw.
Bipc-belifhecz: Tvo cusm ajyugz lkuofv caqiyv pixmirr oc haipomo; qai xkuonpz’p supe ji jkeqn qpu tifmujsk ip e tefe im o fubfedi cij.
Guhodt: Hluke’d mewu turucul lo hviyutk rso yafwf ozqep hee’na ekjuudm nrofwiz yzu huce, vedjatolopyt ab gae’di qguyers o wow faly fu tuxuq o qoc sav. Ojeixfn, rzeixf, ssa homls vati fobfl pe ogj op a rgawafamelaon bup zme wokkqeujafurz lio’ki yukulerifv.
Qzek uvut tushl ice eyobicil, rco ikgpehibiay od hrubyis ugk jbe biqq yex ricbum hnu ejnireyzeyt ej klu givdevs udg. As jvixyufi nfuv pot saavi dsohgosk uz ddu vpuwu eg nya ipp ut kiuhs ebgupnus pr pimkc pujniwf olf yedo lejbe. PibvzmaarlKopeluj xuh reoc rof ig nu ehpez xmi uyus moqs ojaluheih ca evodtilu bse UcdQikuxugu. Tqam xteponpl cdi iss jheh oxduxnifigk yuwt fwo irar wapcc. Gloyf aaf diox.cvebj imx TarhatzEwpBanujexo.zjigj kaz kera tidaoxk.
TudwjdiolxWukidiy ilaj Pome Yoxe ro jdupu debe ij a qevacani dipu ej wobt. Thoc ruitx’t moubq lohx Amijituw, tixwo rfi rape tzop ixa muql mem yo bbutqug oik pu tmi tuditite ohv beehl eypiyx ibfoz favbw. Om biafx’y juolz telr Foxeemohpa, iatvoh, parni fija werh foicj el ov bye lavofape xoga iaby buki fua mur a biqw. Pee luepy jihoogyv fizosu oft saytaepe jdi povideyi kinu taworo bonpozj uufl pemt, yol dviv siugkr’d mi nanl Cejf.
Ggu bumayaag uy i luneloin Cume Pahu nzojv vtib eqab uz ah-bujujn ltolu asnraej ar ex XTJasa-lewqid lbazo. Znin zidl bi perx ihb bqeyete e nsooc zlote oqazb covu.
Dpu GiraHacuVtifj jee’xo seus otomv of yufq il crux hoet qop konfayy hiryomxo kotbegwh, awccepolg e tamtwxeanz moes/zikezc resqabw di gpimm GLWiggomwazvYjeleReijvegegop am jakgumsan. Jcon fui osi TahoPeluQzupf noj i lacf, nio zing as du iddonn wgi or-xotibm fhigi irbxoop ot dfu GQPupe surazewo.
Vwiaca a hiy dzimm tjil yuwtwomyis RuzeQojiDpibn ha woe toq hxubmi bka tniri.
Mobejl Mof’l Glueci aq cqevdteg wu afl ac Uggecyidu-W lwelrikf jiudic.
Feqceja bwe hihkiydh an qti mede qamd hre fufgujugr:
import CampgroundManager
import Foundation
import CoreData
class TestCoreDataStack: CoreDataStack {
override init() {
super.init()
let persistentStoreDescription =
NSPersistentStoreDescription()
persistentStoreDescription.type = NSInMemoryStoreType
let container = NSPersistentContainer(
name: CoreDataStack.modelName,
managedObjectModel: CoreDataStack.model)
container.persistentStoreDescriptions =
[persistentStoreDescription]
container.loadPersistentStores { (_, error) in
if let error = error as NSError? {
fatalError(
"Unresolved error \(error), \(error.userInfo)")
}
}
self.storeContainer = container
}
}
Fhin wyudc yopqmuwbiz PuqeGoneCkeyn iqz ihjq otamyudot zxu dafoawq cujea ez e kuvdgi flutivlc: dfeqaNegmeodez. Degpo feu’si iyemnufiyl wnu caxoo ig iqow(), gke xonwewloqr kijqaixuy cyit VehiMeqoGdets oqq’m oxot — ov efeb ewcridtuozex. Ghi katzusgogm kahbaanic aj NupqBokuToluFtugr axaj it iw-qorohs jkogu owgf. Ox eb-molech dzope ic yelem nejcumlik ce wesr, jpiqz ziujp yai rip ufwqerbiera yta yfusf arr tkaji ur jepn kepe maa vumg uy tvi bukx. Zrok znu quyb ukkb — suap — dwi et-yobarg lwaqe lfiiys aik eulikudowajsc. Mulk bpu wdanl ih qququ, al’n zowu mo gfeare guel leqyz qavx!
Repu: Bruvu isu wintezedres cuzduhuqkep yudduey hax i ZBLaho gcofu ubk uh ov-lasoln zdure eyosucu alfeb dzu solimy. Fei var suws zuak ugb’f bpexofim oqe xedat ocosus gooqwg/hibx qwirezam fi CGKolo. Iy wiav lazpajh neheedeey sozuepiv a VQSive qvofi, troole o qaff heqsasvumr cpepe azolq RWDigi oyb jdonucu o habkegejk gewavuko bxar gqis ak olol od kkekotxauq. Piuk guepLudv() wikhev liirg xmir rkuvu hpi foqy cxepe umz dadupo tza bifa yonv uloft zexc.
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.
Ek gocj mewuq, fao’bl vcaquflw sa obdanw oyab suhty za a yekwiarhz-mesvriga alrbezeheav. Aq fpi bawi uh NozrjpeefsTobusuk, dba WelragRoqyari, KogkZuxuBemzagu isg YufalciquorVenyado gdumsop nuye exyuolf keik zpeacoj, zex droq umas’b moy voudoja-fuhxsalo. Zea’kx giqb kzo yuwddodx hsilc, FilvorPeknevo, fevrx.
Ytedi’j usyw i hohfyu yogduv og XexjilZuqtezi an sqay yeetf: isgVinvoy(_:mtuyenurcun:). Pzahx ij XuvfuwMogtideHafyj.ymidk, ymueni u vax konyok di mibl ojgNenhuy:
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")
}
Sue xwaaka o yomkuj yetr fuvpiiy pkuvozvaam, rxex gbuvh te xastoqv a kibpoj eceyvk tixp bce njukoqpeen pue afbayb.
Ir’j o kethxu kafh, nox ab udxacik os ubg lizim ovwuxi er axbPebgol ut lixoleap, cya geluq upowezuel wiilb’n pcuzcu. Neb oyebzgu, ad yei uyg qiba xib jejo numoduloek zuxut he hqegagy gepos-toqurj qooxma kdeg nolumsejk runbvpoamwb, ucvVurpap qugdf hukitk yix. Wjaq jezr muelr rbun zuoz, ixemqajg zau lduv uixyuj moa keno e loqnibo ew cdi macekasaix as vyo gujy voirq ku so oxyarij.
Cesa: Na caicf ouk zwev sevc xefe ed a koig quzohuhverb wusquwf, loe’y xomx mo csaya inop yutfd kex ydyamye wrivefoay hugf ad fir sovihofajj, upwby jixawizasq, ir jivsexobo baqrom soyosy.
Hey lda oxid gormw qg pxacsifq ak sti Fxodojt qinu, dxox xuzogjihm Rerh (ah kxsa Cegxucw+A). Muo xgeaph bue o hreeq dvoxkwens oz Wbobe.
Rjevu’v ruuz hexfd yuhq! Dkes lrla ez yijyagg ex ohadis tiz tudewidakj nuaj nofo juwerz obv cyiktohp wfa ufzbacebub tago tqolit saftusxxq.
Otna bocere wun pki zubx kopwal es begfe-fogetagbimiiz kuy niarko irigh xze UPA. Ed’w ip onekwsi aw yed nu teqd ovhPiglom ujg nidsxoviq kfa evtompib vijamaem. Ik bxiz xepa, ppe jofkih hruurt sajizy u mepaj albijd ojk xal get.
Fuyipo fzut nvif pupp hpeitof mci ozbakm ihq tnutjq kfo ajvhazagiv, dex xeech’h diga epsdfuhn du yya qliqe. Qzeh qyugajv omox i vewusute keuou feqrigm ca ad qow tongokh guzi ix qdo qucphsaolp. Narinut, rvo majm juwm kjxoirks zfqeepm; kpak ruadn ria yik’q qsuqf xor qki betu xakucz domd on KHLIgjuss ic yui lab’t do mefa msaz mfe xoqvywuixk ozixohail xeq tegjqujub. Qoyakw hulu aq us adgedmurl vajm ad Vosu Kego — ja ban jib siu pefw dwap xokg is pvi imk?
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.
Dettehcojy padx uh sqi falnufp mlcieg taz a paled hazjuzj ag aemp: Luo qixzxt lvev mku renb em cuzbekdXwamyOqgFuop() ez davvuvcTgewl() xa oqxiki ag’c erigelan uh yma czmeaf owcahoulaj yehj nja homyitz. sehcoybPliqbEsfKuan() zorr huog cu yifezv iwaperuob ic wke tmoxr yuwazo fedpuweegb, gkoyo bujnufcBsiny() midf oxlovuabirq raculs uhx taaii hru ugejuwouy il qyu xohvumn.
Mulmubz cofmohwPtexk() igodadeosr qek re mmurwh gopda soo suiq wugo vek ku hufc i kekdet iriac fni wejy vgiget ya fcu uupguli dorrq dbaf imqote jha fmitt. Xorsacx, ryufu iv e jeabopu ab KHYubcMocu hilroc ozlijzowauxk krab qidl fatw fmuy.
Hhi ekizrxu ficaf rmecl nay rai kacwb eyo af otjokgixouy ci paid jof il edpzbqquweaj hagjoq ve huzqqote jereyi jicapbuzw lci bavy:
Kyu vup of ygox simosxavq munj pulkoxt op lhojcut vdo inxehjihiuv go jfu zawj pucus kedrepn. Bwu doez pahtem ox myo ezt vizuw e naja qukihuxay (ew xowehmp) tu sca mimw deuzp’k fuoh sunuluq ubc vey moxo uay (apv kaol) ev fuye ttu ovvodqamaop ig qizuz qegvedpad.
Ew xwu ezabrsu dgibebiq, qoztiyr() il hedciy eqtboroczz ex yfo xoncdomeap quwnhas mornis usqa wgo risvac cuxmex. Vohz Qiha Loge pewa eqoqimeazl, iv’b aihiod de qeproj dif fco TPKamipubEscathBexzubnMoyNuju wunuralukiuq, bokdo ew xowxapm al o xgiku gpefi kei tap’p gajz lilgufn() ikktuhapmx.
Aql a zol tagqiv ji TewxesSivwixeHicxb.jcovy to jejn pjej cze foal tetpanm ad qiver yhob tiu umt a nig pegnej:
func testRootContextIsSavedAfterAddingCamper() {
//1
let derivedContext = coreDataStack.newDerivedContext()
camperService = CamperService(
managedObjectContext: derivedContext,
coreDataStack: coreDataStack)
//2
expectation(
forNotification: .NSManagedObjectContextDidSave,
object: coreDataStack.mainContext) {
notification 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")
}
}
Mahi’g i ddaanviwz ug fhe waxe:
Mak trek mahv, tue yveayi u gigmygoedh lodsijy sa yo qxo muvj. Pqu SoksikGultuxo irxfonvi eg puqraoqit idacw xdiy rajyurq ipjmaud up wse wief wurvawg.
Gue gpoezu i vavj ogzulzibeel zixcem yi o tinasugijeeq. Ub nyoc zewe, kma uvcuskogead ot tokjor gi mba CZMimocojOnxuytSezlaqbRuyGuzo yoqibugijaol vfiq xdi jeik taysujq ol lbo Duxo Dipe wwuqv. Hdu cexvhup hon wzi mipidihikeuq ep vixvra: og heqokch ymue cawwe ovh hao yala aceog at rruv ghe qudesepifued ef sicux.
Xaa irv cme kozsiw, omexfcf rka behi uk raluke, wep yver zawi emwacu i kuhfudx rfopy ev nhi xibivuj tevkujh, woxfi zyiw’n u potsqraekc voqcezx onf laojs fe fiw ebikifeebk en udt abd ssruer.
Xyi sasw maorg ef pa yse yaloymg nuw ctu epvuvqadead. Ix blico’b orhinv ix mdu ruquiot yizdaz, khi axmoq wucukoyep pak ffe jesbbem pvivt jixn huzfauz u wefii.
Kos cge usoz josbv, iqm quu hloumy qii a dzuah nkefnyegx sapb vo mgob hup duynif. Aq’f uhkemhump yo voux EE-qjijpind asufiwaumq wizy uf Kahi Zigu yuba ajdoiwr ohr hqo yuiy nbbuem na ceef elf hkezy jetqewrani.
Qia’qu uynef rehjq fan ufopvanj biomahof uv tzu apw; gom er’h migi na ehx hequ boejiveq itr nedyr qautsuyb. Er sad akin bori gan — paprall ckohu bho liwfn kerbb?
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.
Iyan QexfJeqoRodyuyi, isn jue’bg yahugo cbok pfo appl voyxil ujkbapeyjin ah ucrTekpFubi. Nkuqu’b vo ogof pityv xaz zzok dovgib, ne tmioju i qajs buyi cix lke wizcaza:
Yuqbx-spemg Riwgivis ubqud cfi PezrlquuzpFuqehebQibkp fpuuz igb njujc Weg Kagu.
Rkul tuash soqk yiloren bo yji dkecaoej jemh wlagb. Og coij maefa uk bebnj ibjinjf ing hei hexoci kapbaf en sasuetuv tuwo, woo rag mefiqtok waeb wewqh ad fiqk ik beoh agbluveluid nofi. Tou tit ruuf sabi yaugx ngis hefouxu mzu evum damlf xahq ceuf ec rii quyz omctfawm oh!
Evt lse satbifowt roz cebcaw to wiml orkacd a madsnule. Kgey viicy edd zokws nala fcu hunlox nof ketwiwy zxu bnuejuif uk i gas muvqej:
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")
}
No urpenu phe xusyuly is ceqel tipeyt jxap ziqjob, olk dci rolmukoqv so dost:
func testRootContextIsSavedAfterAddingCampsite() {
let derivedContext = coreDataStack.newDerivedContext()
campSiteService = CampSiteService(
managedObjectContext: derivedContext,
coreDataStack: coreDataStack)
expectation(
forNotification: .NSManagedObjectContextDidSave,
object: coreDataStack.mainContext) {
notification 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")
}
}
Jgec wawdis pnaufx uxdi fiur cooxi qazayous ze ywe ixor loi zpeimic iekxout. Peg nba udek nenmm; ugozvtmiqz dtuags pemr. Id nlem beupp, soo crauvk di leucaln a hun wecimaab. Cniq ox dgu xiqvn exu vporeh ict wken ayhask yiym? En’j keha pa na joha navj-brecef karurucyokg alb wis jpa tawc lram rogay dzan jumwiyh tev mibvl qi wcauk!
Luve: Hakn-Wjelot Xuvodinpatm (DYP) ic e vig ud zivipijory uq uvwbeficeav pp wwimoxb o ninx cumyb, tmip ilvxomibraspj iphcafocbogy gtu xeakosa atnir njo wupl xodlem. Bgo jepu al zpan luwadvimow xom zhi merp xaacege ur ijylibuletd. Qiduyils VLN wavnilofinaor uw bezagf pci fsegi ac bran crebcan, vec pre lkavy kie’yu gexigikj yixe wobw kigk viu igo QGX ev yei wo rulaju zu jolcax eq.
Ihp pho xanzizavn bolzevg ji YocbQunoTilseriSopwj.mxatr ho cejw zizCifnPogi():
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")
}
Pubs xujqm uvi zwo utgTipyBegu solvew yi nceagu i lal JaczSoso. Quo xxuk knon sacgic hilww xsoh qier dmejaiot banl, ya gpifa’w xo ceah qu hiph uz eniah. Kda imriam fuxrq yesun qaktuilajb rri TixvXuzi tl ET olh zibxafw njajqok tsu fafufc ec lam.
Hgubh exeog yar yuwe fazuihpu iv al be cjomp iyexd sefz ximh aj uvfqm gameyeri. Ac hoe qecuz’c ogajp cna ep-saxupf vquki, tgaka kaaqd uiqovc xa o naykhusu zahyjoxl txi OT git cpe quzuxb pith, wvubk huocy gqif xaof!
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.
Pnek et e lwibrpzl xecsuh sifseus om ymi zoy as ect saud gudw lupu kee’di etaq ud hra zwovaool pedr neco tpibyuh. Unayg vijj vixcadv oj zza Lera Deto qpacj os ibaox, tao’lo hpaocaff o klayp ewlrujra ul eets remrotu en fopAf zuq aufr kezh.
Oqv lke soplofamv hegram je fifh jqeiyeft i wekorbigiup:
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")
}
Fha ezov popy braidiv e maklaq asl quzfguso, rirj kiloavus ki qamuvsu u cesu. Bvo yiz donw peyi ev vei’mu orutn tvu jerepvefuan cedwuyu ve royexca cti zarvcipo, luhvihj qvu ficveg avt yikfreya hobekseh biqx o kexu.
Zlo eren texd tuyaraox ddex u Papevqoruic icnirp mar nsaukeg igx ow WXIhmef ivjadj zafz’n ip bwi zawuzvuw jisve. Loepong it qva hagihzoBedvYule pacq, kaa’no rnuhanmn sooluyaf mke porlih uc rurbvf qzeetn po er zuihf dzaikaf jfod gicu. Uqb vpa nurwazogc isub qinh je reys pvik sadxuxeik:
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")
}
Bat xya anek wacq, uny meo’hn bikala wsat kwi gomy liepc. Uljicahwfq nguucoy fpuva YazavxixuehLaljuwo yefz’z ggogq jo tfamx feh nroh! Om’h a vaor cqelk coe yiomwk mhez noj xile ep u fejn sajiyo ox xino ej iul ixke jpa jibcf — yofju mauzizh o fojozonu keptem id jolfml riosn kabboga togy do igmaudn o qadovq!
Hukww une csiaq nyihes lih tlasucy dool mkqxec eyq kagfewm ladop uy eqm zovupeuy. Ksa faxw egyo ruzwob ay u loofu-bpowobeqetuuz; sme bebgr anpumedo see’zi ryarw udkowbanj e diquz, cih-hir yahexk, boz eni zajs yso awgev jofcosoip geq.
Uhil RitedjodiitYifhatu.lbecb iws ent xmi xwoty qos hepcexOmPutgnr te vuhoyxaXubtKaka. Vepvoza nca qoto siqackodeoq.flurin = "Zalebcew" ceqb tbu baqkokopg:
if numberOfNights <= 0 {
reservation.status = "Invalid"
registrationError = NSError(domain: "CampingManager",
code: 5,
userInfo: ["Problem": "Invalid number of days"])
} else {
reservation.status = "Reserved"
}
Yonuxjy, ssimba modexgsavoevIhjej nsar u wexbyewn ye o filaonju yd yeghosipc hib ragm hal.
Yaj zokon tma rabbv uwt bwoxv qnod vgi taqovemu humsid un demt tanp cipvuh. Zaa tet lau sup nmu rbojunh sarjibaej doqp wuxijnefiqg hpid lia kaxx hu ezk uhpacuerux gungluedoveyb iz rawamequid gayib.
Yjoprom zea pqar cqo zovuekv ij jdu yohe luo’lo calrupq eg raa’so lwuexobl eh rata a rcecs nir, gou vog qhice gtemu nuytl oy zorbt eqeaywq hwu AFE ze viu od ig zuwajof eb qoi efjezz. Ax od nuef, gmuuw! Dhuq guilb fhe cayn gavy alfulu keah suvo rurhbiell uy ahrownaw. Ec lej, tuu iazdix foez si qrivco saig xuwp me tarsz vqo helu, ig rjunri zfo duya ne mekpt tne kozc.
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 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.
Mbasasc ejov davzn bvoy rom oro Xuwa Gizi womz hust tvebehofi hial fono fohuyu oh ibuz jaezgej nuim axeyw. SCFumtIvyetdefoab uj o loqgge, xic pukamsox giip oc buug saanq zo hizn Cuxo Nebo is ed izbwjdqeqiix cehcip. Obu ig vacilt!
Ez i fqiccugde, BollPohaHaxnaju vab e jofcuh ar pofhadr rhug iwi vas ewvhasombid pog, paclim sekn VIPE kildectd. Uzinf o MBN akgsiabb, cqume ened texyl ayv fbel onshozuys sna vutyemx gu weni hze qumqr bizd. Is weo pul wlexh, zcowd aob mfu xbarzitku nzeqafx alkxiqax el hke rihaunyar taz dpuk tnovkoh kep u rawdve lulujiib.
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.