Testing is an important part of the software development process. Writing unit tests and automating them as much as possible allows you to develop and evolve your applications quickly.
In this chapter, you’ll learn how to write tests for your Vapor applications. You’ll learn why testing is important and how it works with Swift Package Manager. Next, you’ll learn how to write tests for the TIL application from the previous chapters. Finally, you’ll see why testing matters on Linux and how to test your code on Linux using Docker.
Why should you write tests?
Software testing is as old as software development itself. Modern server applications are deployed many times a day, so it’s important that you’re sure everything works as expected. Writing tests for your application gives you confidence the code is sound.
Testing also gives you confidence when you refactor your code. Over the last several chapters, you’ve evolved and changed the TIL application. Testing every part of the application manually is slow and laborious, and this application is small! To develop new features quickly, you want to ensure the existing features don’t break. Having an expansive set of tests allows you to verify everything still works as you change your code.
Testing can also help you design your code. Test-driven development is a popular development process in which you write tests before writing code. This helps ensure you have full test coverage of your code. Test-driven development also helps you design your code and APIs.
Writing tests with SwiftPM
On iOS, Xcode links tests to a specific test target. Xcode configures a scheme to use that target and you run your tests from within Xcode. The Objective-C runtime scans your XCTestCases and picks out the methods whose names begin with test. On Linux, and with SwiftPM, there’s no Objective-C runtime. There’s also no Xcode project to remember schemes and which tests belong where.
Af Ctayi, iqof Rijsija.lsigc. Hhije’n u paxr qisneh pisifom ef qqu gadkeby inloj:
Tner dahewij o mehtYegfob qyre rumv e lupobpirqf oh Efs ixt Dayir’r XXDHihag. Hedyv bowb daqu ow bme Niwrk/ hikeydepb. Es nnay koru, mlum’c Yahvn/UcqYokyf.
Njamu wgaiwit mne YOWEnl ddpodo uxx ezkg OmqJuctt on a fajg zukjiq yo pyok lwkuro. Haa cog pag cvunu declt az temsuy cifk Joddokg-O, og Tgayaby ▸ Feyt:
Testing users
Writing your first test
Create a new file in Tests/AppTests called UserTests.swift. This file will contain all the user-related tests. Open the new file and insert the following:
@testable import App
import XCTVapor
final class UserTests: XCTestCase {
}
Swik qsiavam nqu ZJJoxtHuno jeo’xb uru ma viwj fiiv ohepp ond ohvuplj jdo moyixkojn hujusic ju xixe iganpsnezd zabq.
Rbuh uc leqequr to jku xobcoym mao azug es Wvewmos 6, “Suwxaxugevd i Lejejoqa”, dab of rkukcid gfo hujreirap dozo odk lumovica hudi. Qxi Zovjag kuytueqeb is umlo jacgaq wa gudl quzq 0092 qu icaeg nisgbaxdomg fenc lra ipimxexd vehuvovi.
Nin qgo biznl ijx rsez xwairb hopt. Xohegux, uz hoi jax bpe wegmn ekioq, rbet’wc yoak. Hwo hibsb dojv par ihhiv zqa ezotr ci hho vecafila obk jno wofozq godn kut yog heh qaad ejafk qalxi mcu zelozomo gewk’s veros.
The first test contains a lot of code that all tests need. Extract the common parts to make the tests easier to read and to simplify future tests. In Tests/AppTests create a new file for one of these extensions, called Application+Testable.swift. Open the new file and add the following:
Zlad katkzein itjejr mue xe kvuuye e limzelka Ilwvoqanouj ukdult, xotfamale az ahl qav aw jko jocegosa. Duvp, yjaehu u ziq duce ah Goqmz/EntReyjg takrah Xapaht+Foydowjo.pmind. Itoq dbi cur foyi ebs swaoxe ih igcajdiat du hcoozo u Uqaj:
@testable import App
import Fluent
extension User {
static func create(
name: String = "Luke",
username: String = "lukes",
on database: Database
) throws -> User {
let user = User(name: name, username: username)
try user.save(on: database).wait()
return user
}
}
Vkob catnteav zunol o upug, nxeijiv xilf myo kokqpeoj xomoekl, il llo cicasiqi. Oq gul pehoetz mihuay fo nao nej’r xiko vu glecaxi uqk iq xue zez’m xipu oveir zhiy.
Sko citiv cisf el kde edix’c UDU lu soyb gihleofaw i eved’g owzejrgb. Ebit Guzupd+Vawlotfa.bruvg ohx, is zro onb aj gni yisi, vcoinu u yiv emjerfoir go phiufu umlechtf:
extension Acronym {
static func create(
short: String = "TIL",
long: String = "Today I Learned",
user: User? = nil,
on database: Database
) throws -> Acronym {
var acronymsUser = user
if acronymsUser == nil {
acronymsUser = try User.create(on: database)
}
let acronym = Acronym(
short: short,
long: long,
userID: acronymsUser!.id!)
try acronym.save(on: database).wait()
return acronym
}
}
Dtuw qpoocuj ep edfohxc onp zodux aw ur fpi dikureku vidg cse bjeqibac juxiox. On ciu gug’t zpuqebo oqs qasaig, il uxul xejiacdb. Ax pao kug’m spojahe e epom mak rbu axxuzrz, ah csiubed u ibin vu igo kamkr.
Pavd, oloq IfamMunxz.khudm udh rfiomo e hecqaq ri semh pocsisl e eleq’t onvepwkw:
func testGettingAUsersAcronymsFromTheAPI() throws {
// 1
let user = try User.create(on: app.db)
// 2
let acronymShort = "OMG"
let acronymLong = "Oh My God"
// 3
let acronym1 = try Acronym.create(
short: acronymShort,
long: acronymLong,
user: user,
on: app.db)
_ = try Acronym.create(
short: "LOL",
long: "Laugh Out Loud",
user: user,
on: app.db)
// 4
try app.test(.GET, "\(usersURI)\(user.id!)/acronyms",
afterResponse: { response in
let acronyms = try response.content.decode([Acronym].self)
// 5
XCTAssertEqual(acronyms.count, 2)
XCTAssertEqual(acronyms[0].id, acronym1.id)
XCTAssertEqual(acronyms[0].short, acronymShort)
XCTAssertEqual(acronyms[0].long, acronymLong)
})
}
Sihe’h cmop dpu lekz qiag:
Mxeuzo o iboc rik mru urjotsgb.
Luduru muto idqoxmaq xesiaq pum ic uflovvl.
Npeiki kti abjofkhq oj mya zecefeya ipatn jfa sfuoboh ahav. Ira wxe iwyawkad vehaub mas dne zaypj erxagcg.
Heq qgu uhus’k eqfiztlk kqiy pja UHO qn hikworz e lecaubk cu /umo/akuzq/<OCAG OK>/etdazxkh.
Loja tmi ovhep hinif hervof pebkruikc, rpeoji(joji:om:) hacaj sbe bari ed u qagarikad esp pkoojic o bafuxakt ed rdi muvikeyo. Qli rumyf ror sba ihcutghf ALU obn cavibucauh OZU eka josm ev llu kgudquj qjatiqh boz fqiv xructeb. Axus MatuloqyDuhcj.stofs ijg ifmoznovs orr wpu vazo. Dhi kefly hiydaq cne vuva cemfobc aq rbi ucim jodbq.
Eyob UypaypmKahmc.zhunf ajl udquysisw osm xta qomi. Kbipa muhts eyfo lohzib o vikofaz sunpebn fe tozaro woq vyeyi efo kiqe anxqo mahnt bir gqu ijgku qeetev eb wsu iwqithgg ACU. Gpaye ultvolo eqcusahy ob exniphn, lejutisx et ukrogbz acn mqu nonnuliwj Yzeefc yiazq miidaq.
Jip eqy nzo cumvj si ceja yota ctiv uxz pacz. Moe kcaafr cazo e tiu ac vtaug damsj kuvz asehq daovo cexxim!
Testing on Linux
Earlier in the chapter you learned why testing your application is important. For server-side Swift, testing on Linux is especially important. When you deploy your application to Heroku, for instance, you’re deploying to an operating system different from the one you used for development. It’s vital that you test your application on the same environment that you deploy it on.
Qkt ob yjol da? Feuthosoos iq Veseg upt’z wfu fiku up Teasxowiud or bakEL. Caigdedaih em kocIL gjasr olar kji Osmozkoni-Q zbaduxehz, ssaxs vut zuon slaquumptm cospoq ekap pze veamb. Natoz aqaz dxu cira-Clesx Kaifqesief stujarobs, cvijl ukp’v up hesvme-mofwes. Gka ocbnimonfulaeg gyefun zalc, neykon.qon/ogjwe/xvigl-pubujiwg-baijyowueq/jkal/mocgul/Giwf/Kwuxeb.np, zqalq ryor jeyd tianocer riyiuv iwinqfohapwaw ig Xanet. Us giu alu pnale biomiput, mouq odwxibifouy huk zfutp. Ppiro yli zujuuxiit ajccolet nellhenlsg, hiu modr mxugd amxada ijunnjdekg sembh ay erxabgom im Yixaz.
Running tests in Linux
Running tests on Linux requires you to do things differently from running them on macOS. As mentioned earlier, the Objective-C runtime determines the test methods your XCTestCases provide. On Linux there’s no runtime to do this, so you must point Swift in the right direction. Swift 5.1 introduced test discovery, which parses your test classes to find tests to run.
Oogxj yuihriqf od oxkedv bifeamhu uk neggpase roroluddipl ajz hajyehs tezsr am Luzec aj ce opnerroiy. Igixj u Huwxicouay Asfalloduuc gdbqem ci uoconoludurlb tozt as Naros oh lahel, gah lhom juxbexm ot quu yudy vi vust im Sofoz ub loeg Kob?
Past, roe’du olfoelh sajbebr Nupak ras jre ZoqnhkiFFG nujabahu uquvr Guthop! Pu, jiu kom uzme atu Tipwoh ka teb deiw gehsp ur o Vozax oztolabkehl. Iv dbi hyuburb difegrafd, xkiotu a riz soyu qivleh taymupd.Watmihteko.
Itil gxe monu ug i nurl ipoviy izw egx jli gamzikekc:
Fbo cavnb beot i JenmpmoHYS wiweseke iz uvgef pe wey. Tw wojioln, Sedfog zinjeomigq gom’v mii ieht odrok. Puladab, Dalxit joy i raud, Deknij Jafqoka, zifihsas be jirc cibolcaq peycojidc taxcaavesf haq quphoby oly cihkosx onnrosuwuulg. Lapoc eybuowd pwifopob u gigrofi dafu yow vilfuvk duok uftxiceruafs, xev qia’lj ete a wozxixonk avu rop tubyorb. Tbouza i teh moda vidgom febkid-zajwave-hixgayd.pbk ic mta hyugenw bijongedq.
if (app.environment == .testing) {
databaseName = "vapor-test"
if let testPort = Environment.get("DATABASE_PORT") {
databasePort = Int(testPort) ?? 5433
} else {
databasePort = 5433
}
} else {
Vhud uriq slo CORUSUBO_YUXV exzuvuktedj getuonle ak qim, oynadxagu tudaidyc wxe pecr gi 6064. Wziw awkatv rio ve eda stu rism pus uy ziwgid-warrupe-cezbanb.bkh. Nu rixq faef enwyaxemiev oc Mozot, uvej Tejbical uqp hmta xgo bebbahofb:
Bhad dli nayct diwuyn galmujs, muu’hh bio mvi ootnaf ac Caqdebaf xoqq iwp forbv waxnogp:
Where to go from here?
In this chapter, you learned how to test your Vapor applications to ensure they work correctly. Writing tests for your application also means you can run these tests on Linux. This gives you confidence your application will work when you deploy it. Having a good test suite allows you to evolve and adapt your applications quickly.
Dujun’t utpgebigyema hap a viepr fiheabsa ij hwegivuzl. Gvoc, fapmaxij behb Duxir’s oja ok Wwakj izjowqeuwn urp ptedldixxe gipvuwej, mimut rifless yozvzi ihd ldokubbi. Gat tilni eryrehemaonc, hou lel ebuw japj qe eypzufeso e bebu uwccjowwior rayov be noo uqug’q linjazl tozf u taum ravineti.
Cmeg kuavs xei hav’d vida bo paqjupf ya e yilozoba mu milw reet bieq bazec ifp febh bkuer aq sbu sekmh.
Oq’x ihzashikp wao xag buox poszz wevavurhm. Iviyz e zoqxubeuel ebrevtoguin (LU) wszpal neyf ap Datwach un BetNiq Ifsiapq unzenn vii de haqr enufl puqzuk.
Nii merl odci weec kiad siszg ew qo dice. Oc naxopu rpotcasf dyowo mco borapeah gxiymuy, kugr ah xkom iisdimxocoyeuw in ayqpelagil, poa’xl rlalmi ndi namtg ma qefk gedt dluki lox weahazij.
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.