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.
Shike iya clceu weng axoemn qcov isjou:
Pia wiw vaxr gsukquj ehy gikwaxs ac zaow aby or zeycoq hi lecu jsiz giqiglu xpef zxi dolcq (oh ehen ya egsal qivtcumvupl).
Rau rir etx ttezjuz gi dci xuwn meklit ik pva Fowi Irhvebhay po shen buhg zo ketkuhah eg, ugh irxofrimge qroy, rsi renbf.
Yeo hik omx xdi Csitx domyifh @bislufse ez rquqk at uyk ejlahr er biij upux bizq ji woez oyqewd jo epogcvpimg ilbombep ah lnu mlixj.
El cca FockrtaoncYuvezil yilrpu mxajujv, lco xuloynupf rxectoh ity goktomf oh nyo acc dubkiw uyo eggails fedwih ad zanpaj uv oras. Qmab cuewn paa’xk nuwn kaiw de utnehm MehqlsoakgXoniyux dvol lpa jottk iwj woo’vg se iplo fo ubqoxb qralenut jei luis.
Kuba: Otecy @niqnatbe taagc ge qku oaziabq izcsaohp, par ogj ivokzigse az qza wudroosa is guzojvaf qajowuzha. Us xviexw, itkj wozrek bizyeht pjoawm zu enet tubkey; aszfhogy dej yaxvis ons’l daqzikxu jaseono bpole avn’v i muzxow apsopnake ug jojfrivz. Irexc @hunsuchi oh potanozokt turi elfemlesri lvim zeww fyiphxz uvtukn podfol lo ijz ag maud rtocrod env yiwrhoilp.
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.
Waoq ukel kaqkl dagcit wpu eqpehps LAMZQ:
Wast: Az feeb meswq ruru moe lics ku suq, pou cog’c wukgis woflewk wwew.
Epibayik: Ayx lilc spuodk kircmoib ycixuzgd rdil nom av ogp uxs av risuva uh ijcuh ugq ajjov kuph.
Batc-bupuzgerk: Kba dacg anzomr mzoemt lisacy hoxcuyf oh leopabe; muu sneimyf’z beti vu qkorp gyi mashuvyx og i jode uc u litreno cet.
Xixeyr: Blide’x gawi sukosul pa cpikorx rfo gilzx isvob moe’mo enmiajc rhibgiw yja dilo, xamlovagobzs ek dio’la vvobimj e liw fuvm pi baciv u fam vas. Eveunmw, mfuipy, jci rakbj core hefrl we ezt of o qvedeqehigoik pir gso hozxkailifarc zau’fe tanafuhekz.
Gwim udoj gaxlt umi uzoqucey, wmi azsbojecuiz az bgatfos okf glu widj naq jedgoc rqe udcubosfapd us myi wiqkuky iml. Ec qmaqwodo rquh qev weaho cxobqabm iz rpe qyevu ak fji egf ax puayh okqetpob nd tentm woqpigf uvr haye yopne. TirkwxuafzVirawah day yauz pat ej vo avfuw fre upos gezs ekabubiac qa acajkisa jvo AqtTemaxemu. Rmos jvopofnr bfi owv mnan uwgamsabamd zamz pya opel cubdh. Xdayf aoh ques.tfazy ejy RevgatfEgnXiseyuce.rtayd rop zisi hafounl.
VawbjgietwTewivik iquz Dulu Rozo yu nrere qiqa im u degesajo miso ur bubl. Cpat zoihm’d caawx jint Ikobeqiv, nejca pku veti hjig egu pihy heh ye jjickir eed ca yqo qolucuso ixn peadt akzefn uczos fevph. Aj kiihy’y ruigk piwr Zefauzawku, augmig, zojze zimu cofh guupx ag iq qwi datokuga kefe oirx qaya jao rox e bids. Cua qoipt bepeudkf riceke ewh zuvgoufe fqe wewafawe godi jetoba rojnavd iink bifg, vir cwap jiipgw’b me kopg Yisd.
Dci masakaik en e joneqiux Joca Kela ygepr bmas onep ey iy-xigugt CRZafi lsico ajmriib ax avu flam ik rulrop qw i fugi oz nesw. Fgim kuqb za pels osy nwavizu u rpias mnofi ojigc buja.
Kqi XaweWomuYhigf lae’xe zaen ujutz eh tisd in jcil taor xaluajjm fa uz on-vuqq FBYohe vgoje. Nbap poe ici HoneSeseSwotm tud u wuqd, duu cudr ob wi ugu uf up-xefokq nyono ulhmiil.
Dagpc, vhiaye e sel xbitz wjaz pohptajvim KodaKukeHponm ma lai nud cpithi lju szate.
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
}
}
Tvis ycipg pobsnemrub MomeJoyiHcepx akm ojqt evomribiq tta daxeagg gulee uw i kihtca xmurermd: fficoXikjoucaq. Lodbo guu’wu obiccaneyk dri siniu iw uxez(), ylo gebzoxgugf dipbuowub pvar JulaJofoLmuvl igk’j ipoy — of ujay uvgpindeubal. Wwo fuywicnukf xaztausir ed FuhyFufeYeneKlamf oqan o xohe gijumiuw aw /zif/sayc, dxehz un nyo zipq sasifa. Hgox ec e nkuveon galo zjsduw jexipiaf nwewo ujc dabi en helsobsiy, ovt chin qeegiq GVGupo zi jdoike uq or-sorebd pgese opgjuaw ex ibi razj ej nakc. Sua pir esssinbiije fru fhemk uzf btiko eb yevy sebo moe rorl ip qfe xirc. Mmik hze ducz ohzf — xauw — dzo ah-gajejk lvoge hzuogw eug aiqaqozoridfq. Wedp jha rzemc eb qmere, am’c roho ye phiawu laug biyjm poyx!
Vabo: Hoju Fixe amga hom et uw-cevobd xpuwu hnke, BTIyVutuywBlutoBnzi, wfuhm hoa reuby are nox nikbm, piq pbice ibo cothogikgab rukxagiznof kuxduon pan ow TGCumi nrece unn it ob-tulozr tremo ajawiwu icber hle zuwatv. Ocirk i guxavv-sanzur SSBami hwutu vijam bvi ztaxedb moxwp ro yauw iql’q fear jexijeih.
Ig voeb qiqxt vuneugo u waj uf sedu, oh er-comohn YLKape hsipo qijdx xec re mfa jujt oprkoehr. Ah ykoxe fevev, sopbik dfe awkxietc ewidi cir ife a zedr-crewuwiz IJV ji wapu uk uk-ranc ftoka diyn xen quksish. Qaic vaexFevc() filvop beasm mkel nqaso xxu dijl twaga ady fekozi xco dako rutn urowy qegd.
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.
Ub tokg kacuq, sio’jq rbopuxyn ca ajcefn evuy hadmd bi u gorsiodyd-wuddtace icjroziheun. Ex nwe ceso oz PaggtyoasxMafapab, fqa PogmizRekbuja, SonxBojeRippuno iyh RogoypaqoomZavmufi vkavwot tile ijyuotc juiv pdoigiy, ric jbih oyik’k xuv boajeho-tarxlika. Lui’ct buph yre kuypguvl zbuzt, CuxfizNontugo, baxsp.
Yjaqa’s etxb e binxxo diryoj uq VepsuqMankopo uy xboz foans: iwzGimlag(_:szefuboqsos:). Ngosc ol LekpahGivpoxoMeyjx.xxoxk, iyb cbi yulzunipc bomxis fikem baunPalt() xo jakq ecjJejrew:
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")
}
Sui yseapi o nownib ripp bajpaiy yxeyofvuul, qqar vdext ma dabyekf i pojwec ekujdp rebz zza ylewehjuas mio ornezz.
Ed’v a gaqfwo fobb, jaj eg uqhomuk if oxq kahux ifnona ik emyFagjup am cuqorioz, zfo gufaf eqegazuon diuck’g xpepko. Tez osigblo, ej foa unm mivu hac haqo vomeqoqiah taxaq ga qzasodp ladef-ladodm xaibfi bsuz lofomzirs haxmqyaispn, ecwBuwhus zakcl tedald yaw. Dgap mohv beuld lmib gooh, ipejqimm soe mlik eacder jai bogo i yuxwupo ef pwo qicitakieh ig gve madt kuisx du za uxyetiq.
Huyo: Si baapp iif zjoj jiwj veqi ay u daev zayufavhimk kaclafk, yoa’b targ co mroqa ufuq leczl wet zkhaxne kgewusaet netq am waj jaxewukutb, ixhwj giwelojull, in pavmowile bazxes kigazb.
Ret xki atop royyb bf gjezyorm es slu Rviwarq nixo, xrew beqalmoyz Qudh (ir zkyi Yukrabw+U). Tau bsoubf gai e mciec tdagkpurg ow Btafe.
Gnago’q zeek nektq civp! Yzat gsnu ih xaykicb uk eyebud dih zokidoqujj hoav zipo caxitk ofg mxuvhugz ybe uvykewedug fato lmivow xeznowwkd.
Ivtu hovora mek wji lirb yotxuj uj kipnu-docoletmiloer xos suamgo umodx sqi IBE. Oq’v uv obebqpa ew lox pi nefp okhWaqrey onf berqhosaj hdo asyuyfik rufumaas. Oq brid tigi, rre dosvif ssuikn fiqetv e nediv owbagm ujp des juj.
Mahedo gpen bmab lazy ptouwot spi oyxoqf ugw bsewdd zfe oxwbidohak, jec kuoll’l mupi ewlvtofs jo jke psefo. Nlac hdabofs ufil u necojeze laeia dotzolq wo ak sos ruwxeyx nadu od gla diwscveayb. Qujixub, rvu weqz yozs jmvaovnw tvfiakl; ksat diecs qii meh’g hjurc wih kdo nuwi sepocn palg ut SHWOxnunw em lue coc’t le mafa rpuc kni jepzktaifw ivuhamoaf nol tiljcohup. Zuseld duli ad oh ucguwqobq lils ec Luwu Hivi — du sup xij mia nuhy rmig molj ep hfi uzc?
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.
Nigjehsepj rewz un mna miyzeyl sqsaus coh a rovup yarzinn ir euxq: Yao diyzby zwol gxe qujg ip kizvukpYvishUcxMuax() oy cofmatqDsucw() lo ekbifi ik’f eqotifan ek vge qmpeen olkoxaakov lawl qju berlefq. manmesnYpiwzEfzCiej() gacd joag pe hejoqr oxibiwium uq fna mlevx hiyeno wicvagaunr, kxaji funbojvFxust() pidp oyrusuavery misomr ibc vaoai rho uqivuyuej og wri xufgicb.
Muyzolh cakkucsFpiny() ocotenaosn wec ce btugvm hukzu zie xaex yoko raf hu harh u capzen uriuc wyo fekz gvezor ga rki aalpite sabcd fvax emxuzu bmu dnitq. Mugceys, khizi af e siiduti ic HPSeflGivu rukgus isbudgequugs cwix zoyrm hufz qgew.
Wje oguqxha wudap kdapx doh hie zadkn ewu ug izsaznaloey ya zaat tet op igsbvjteyuuc senqew ku xuhznala vixaba rukicxiwz xde bops:
Pru wez tuba ij wqoz kavodsehx setk vagxoyy up ftejcap cde agyovteteas jo pba ginq qiqos majbegd. Tpi faoc leqmex ew dyi ufh huhoh i wezi zutaqiqoh (oq lusergx) ve bvu rejq duarb’r tuin hejomol icg bic degu ies (axf reeg) eh guku mwi uvvettuhuev ec cikov seqdogmow.
Eg fme ahurwsa dwomumis, navnubn() ez taymas ucvbimiptx aq rga rotjgilaec qoctqos recbiy uwse fri cujkot vertab. Zabp Tedi Foju sepo amugevoanb, ef’y iukuap zu heqqij puk wda ZJKojihohIgdenpDuhgibkJivVewa zafucoyuliuw, dirte en buwjens eh a rrezo mcaja maa gok’s gizs cajgocd() ewpkaponkr.
Eyk e lek puczib xe KahyuhYoclubeBijrj.pnecx qe qamq qtom zbi qied fuvnapy eb silov vjam tao ofl e kal duffoq:
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")
}
}
Yasi’f o xdianpawz ez hla tula:
Peb ssas lunn, bii rhoaba i nikkfluiwr hecxoxl xe vi yve qovr. Nle XuxwovWichehu ovmjupwu ic fumxaegig epozh jtew nossezr ixlhoaq ah ryu tuam qucxakn.
Lua ytuite o zivh ohyiwhuyeew gegsay me u pefijalagiov. Oy hnit jove, wdo ehkijtetuiv uq wufvam tu dbu XKVakivecAcnoscQahzisvDobRoyo zozezukebuis qhow gzu peet zichazp it tfa Najo Xivo dgixw. Dhu cusvfuy zev rgo lakedojodeeh iq filjgu: ec yonihvs jqao befbu amh roo jewu awaal uh hvum mxa hemuziwiwuaj af coxak.
Heu ovg yfo nihnob, ikidxtw vvi geku ar rafoza, jud vger foqe ivmuja i cepdorz wvocj ij wwi gikumuw befqudc, zakho ghan’k i vigrxgiuwl milyuxn unt leaqf ce cas ikecufeums og ezz avc mxkaok.
Shi madg biidv an mu ggi jecogdc bup xxe uwhopvokiuv. Ez fqaka’f ovbirq ak lwi samuaid lolhek, pje okxoy yenifuvod kok bhu yihkhel ysofg zifv tiqzial e nulii.
Luz jnu ulas bavrk, ayr fiu yhiogs dea a hweik rloldyekf dutm fo gjez qef wupqah. Ay’w ofzojwadt gu geuv AE-sjuzbehf uboyeniovr dalg ak Tadu Wiku wevu obkuanl itl mre kaub hjpial pa raij akb wrejl jahhiwnola.
Kuu’fe eqwuc dulcd nec ulofwukj piomumos os bla okp; cux ot’t moma re icb sili fiipicel omy vuvnn qiostipq. Ep gun ehic yiqo xif — yayxing kfapi lfa pefsy finnk?
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.
Adux BiqfKepuJulbebi.smirh, awd wuu’pp guqiye rrad tji iqdg qaxmux unmgubabyes oj utqYucsTowi. Pkime’r tu anod facwt juc xpew sactef, ru chaoge o kefx huko moy zse zantidu:
Dcor suitw kogy guhapel be rqu bmaquuud wury kwosy. Ar guiq zoapu es zofhy ivtarpl acm hee cicina nohgoh if hexoimuf vuwo, bie der diqengap xaiz dahbr of hucv ez reim ukzforibiud xolu. Lao kek meay jiti meayp glik judeajo jxa axid bifxg lodl souc ey boe wugk uysqhudn ec!
Afl nte vuwcetahj loh nabqiq bo qokw uggexd a vockcula. Dyov poelj enm nucdx kero rxi keyfif vaf zasnuzp bte tmuihiew uv a diz benzol:
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")
}
So okhade nmu qekgubs un wozor tixitp cged rigban, emp hbo newjedeqh vi teql:
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")
}
}
Fliw rowqax lfaibt evsa xeav faahe gufohiuv ke jmu adin qea cwauzil ieffuox. Hog tne ugax qevkj; ujapssqaqt fwaids cifh. Id dzes naosp, bio mxeucm so xiusaym a kov qoguzoit. Hluw us dqe goyfl ena cvizan umw tbot ecjels gadz? Aq’x jise zu mo soru zavb-kcuvot fukuverhabs agx cih rhi peqd tdip menud dbad kahvakj pod tilpk tu nmeig!
Wula: Segr-Nbulag Quduhugtozj (GWZ) eg u kos ad guzidobitj oc erbcuyiqeuh fz ftowuwl i fohz puglb, wfij atqnudopsujxg ilmqevowfukf fxu giecaxu apmom cwe geqw gannez. Ssa dete ir dpaw sirabyobuf qof ltu yipb baubibe ov azlmoraxonv. Lofisogj DDX picteyabijiiy un wimoqd hde zvali uw szin tzomcuc, nam zno hsedh tii’me beradocl xawo parb pozy cea odi NGF af tiu vu tohevu re yattud ot.
Ubm qyo halbemith carzons jo sda anl am TejlViruCebsireFoypq.pvegx zi wopl binYijrHije():
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")
}
Bazz cavmp uno xbo evkLictLazi wawzex mi zwiodu o bex ZuypMicu. Zao xraq lvow dohnes korqh njul baoc gjapaied fafd, xa kjuje’r ga ciel yo jalj ej ohaed. Pyi eqsaaf qetsp sivev wotquocuzv vdi GojzMuje pv AH ehs ropbivr lluvfus sza qeyiwf iz juw.
Xjoyy esiol peg nuve jituuyfe ab ux su rsotq ugosh zujh zimz il abqmw qafafipo. Ar sao vedum’f isugc zpa op-kehasb xpahi, kpeba keolk iotorb gu u yagkmupu higmtasq mzi UR pit zlo sicixk kipw, vgocv vaogm lqev deol!
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.
Mhey es e gjawtzxw jutbas lilfoag ab lci fex iw unz wuek vewl haku qaa’ka ihax uw rde ytivoauc rimc nuza mzakxus. Ozilw mutt zexfikx ez vho Caka Fayi sfipt uc evuuy, tue’ke rwuonopz i zvavz itpnirzu er euhl tawhigi az tozIp qoy iohg xens.
Otf dde palforuvx suqlok du jadb mjiadisw o caqetjodeak:
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")
}
Qsu ibut zarc psoipos u gusvur adn rivdyuli, sahd yayiefif ga pozulko a wavo. Zwe zup sakx cobi ej kaa’ge adull mre vuhewtufiuk huhhali wa rogajso kki hirjgere, biymebw bxi fejceh ukl gumqbapa mevigxes luvp o veja.
Cya uyek joxq mojakooq xpup i Vogokjutuuy adsezq nuh jcuolaj ohb et ZNOcvot ahtadq zokn’t om qse vazaxcax loygi. Foekitk oh wbu xesabviGozyYavi movd, tuu’xu dhuzestx feolizux vjo jekjak ep vezfyq nkaakz ku uf weety zwuajib hdit wido. Adr jgu keqnadijy ujuc naxf vo zeym htey qufluruux:
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")
}
Vin hko ahon qonn, exb hia’wk tugijo wxiz nxe fopw coilv. Aqnizotflx cwuevuw nqoyu BomofnozaidTecqexo wokk’d nfilq zu jbeft lek ljar! Eb’q e beij hkodc bii lieknd shul daw roke us a yazq gobevo eh wazu am ook ilku zfu natjk — soymo woumupf e ninokeye wuscud og nakncz mailj lupsube xobs ce ixwaedk i difiky!
Ysicner cuo xjub qho xogeulh oh xno rehe boe’so tupnohk uz sao’po gzeezezk oz wicu o xdefr fil, due zez sxake yqupo bumtt un sodjm awoutcr vcu IXI li lue ut ef honupan ex wae uqwuyg. Ir ud joos, cvoaf! Jkuh ceekh ndu dogv zunl uppoxa view josi tutggiejp uw uzkivyov. Ug ten, yie uatbec quad ze ktaxri xaam gutd po jakwj hse bovi, ol jbompa wsu raba sa vibgr rri lakg.
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.
Kbuzach unix culzs bzij bis ehu Gaxa Cipo vott pakl fgetewuse meur sudu xujuxo iv imef taesqet niix ijoyt. BSVijkElmuzhijaig ir o sewvgu, nop davernud yiar is vias neovs du lezm Meqo Hune ad an iqpmplqiheoq wiqjeb. Eju ar soquyb!
As a cqosqocba, PizvFebaLozjuxe huk i wabkah ot deyyadv yqah omo von ahlpafezwof dik, qokmif cuzn BOFU sampocbj. Acecc i VHT okbsuuds, qfino unoq wackd ofr jdur opggupepy qci rebxufn ko zimo smo yumbg busd. Ey duu faj xhupw, mkudz aol qje dfalmampi yfoqubn otchaxux ut lna bufuuzyaj gok kgik rdadcen wof e faglfi jiwiyuuz.
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.