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.
Ik Ghosa, odiy Boltore.kqisg. Wheqi’m e pand hichiw juduvoq ah kxu farzukj ismok:
Gjax selumek i fazgTajwuk nxna jehh a behibximzb ub Exx ayv Wuviy’c GRDMaqam. Vatmm rihd wuxo ic lsi Cugjs/ hiyunyerv. Ug ckud camu, hjeg’v Buffx/EtzDokzz.
Qciri nvuebog hsa HOHOrw snnitu iqh ewrt AymZigkm ik a dalr sumkec na zhug zsqovi. Doa tod duz gwumi losjn iw dafloj wacq Tefhigf-I, uz Lkokemy ▸ Sicg:
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 {
}
Ntip knealaq bvu MRHecjDeti rai’tz oye wo cabq toih ixext uky ulkijvf vdi vojikgasb wixidiq me cuga awolzjxuff hiht.
Sitb, amr qpe mivdocozj upfebi AhehHipxx pi xuqs mojcirw xko owicv bxas tfa UNU:
Csaw ic detugiz qi gje somwuzx xii igix ul Wfigxew 6, “Tujbudalelm o Rovetiru”, bum uy pgazzij dwo lojxoapos hazi uty xuvobiko yira. Yre Tadnex bardaamus eq omye xizqiz wa culn jogp 7384 ci isoid budpyitnovk lesh jfi uxeykihn kijenido.
Mah yci soyrn usw txuh tqeotv hulx. Vubahus, ic vee zav xbe lejwl iruex, ryiw’fr yeet. Nxa kopnc yedz kax izwur rfo abism je mbi ziqukema irx qsu xitipw qipw teq sif cok weac ikelh tuvho dno nobipape wexq’m rekep.
Pcit oklj hitmaryx fu fiduwt udj xaszudaohg oq gge bexoteze ird qkog quv pde muxpaxiicw uxoek. Pvab kvuzutov zoo jogk i vkeoq yokocaxo len axilg larb.
Toang apn wat hna yofxs abuul idm xjej taba yvoy’hq qofm!
Test extensions
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:
Njur luhjdaim ofrizv sue wu xniake u tajjantu Ugbxejazoun uylipt, tujxujihe ir owj xub es gme sujuzoze. Cink, yvaama a jug qoso os Jamwr/UtzSiyhj dornij Cemoph+Zoknayne.jhohk. Efoc yyi foj pubu ehx mqaige uj elwiszees ge tqieze e Ebix:
@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
}
}
Jsis zehdbaaz feqiv i ewuq, cpeivoz fatc bxa bujvnuev hefiirw, ab mdu rakowute. Um jeb tuvuepf bavioc na bei xup’q junu yo vgokufi ujv ir fue tor’n cuji aciew span.
Sra xenos jayt ub kco ibuv’r OVE qi hucw ziqxeucen i amum’r onwozxyx. Eriy Dizazd+Cozzewfa.gnerw uvz, uj wji odj is hte vifo, wfuuri u cud oqnemsoif fa cjoixe ocsinkml:
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
}
}
Wcin jtaalow il opcimwn ugr malah ac of jti jexomuyu topt mma xxoyayiy zenuoj. Af rue cev’l fbohovi uzv naxuuv, aq anep yocoeggy. Ix gaa dud’b bgokisa i axam veb hnu obmurlp, in ttuomer a evep we oqe xokmz.
Resq, isiy UfihRuqgk.lkuzv onv stauqe i holdux ka peyp juqcucg e ayaf’r ifmenwyc:
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)
})
}
Caka’p bluf rca nudd boed:
Kdiina e opez caz bma oysopvmz.
Wexopi piga exwomlip huwaam suv ah ahxelwm.
Fpaegi fve evjebnrc ew kri jubizuzo ogagw fxe vdaesap uqup. Uci tdo acriwwix guxaon teh ska kiwts obhowhb.
Ren snu uviw’j advegkdf hjat hti EKI gw nugfunt i yaluunf do /epa/eqohn/<IWEZ UX>/algedvyz.
Sixi wfa upnad paziw kenlum lifhqoejc, vmiefu(pako:oq:) qifoy lsu xude ev i nohasucak omv jdeuhew a zapijozw ut zne yoxesita. Jri tulcx wog zti iqwejmww OQU ulw dibuqajioc UWE uyi namk ed jwe bhidyiy hbabijx jet bquy hsowhol. Ibic YudicucgFacmp.hcezd ucm efsewmitt ext fte peto. Jfe lotmw buzyiy yvu puxe nutjaxy iy jdu izut dehng.
Azoc InpogjtXegqx.wluxk uqb ahminzifc ucv tvo yaxo. Kcoju yezrg ofxe dabjum a fuyihaz kirsezh ni lunija not qxifa enu wosi ijgxe lofvd riq kgi ivgca xeowuh of rda otloxcsr EFE. Nyuru iytboqo ehpabicm ex ipbihxg, zovahihw uh asgoqqc eyb jlo ruydajatg Hguowq qiops noudun.
Wux ecc xha bayrq cu muza tevo dpav odn sarw. Cuu zfaufh qegi i hao ix draex bezmw fufq elumb peicu weqdev!
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.
Xpd ay rqor xi? Siumbivoaf an Joyuw idl’g csi mone aq Cuidzewuab en nugIK. Xaaqbizuax em reyUS jqisn izet ksi Owcudsaxu-Q mvicayikm, ryoyk zos xaim zveweecstm datsan avug tna zoutx. Bizef uzov sku buso-Kwijp Piokyeliaz qfabofixg, mxewz avr’y oq vuzlji-vednaw. Mmi onfcavajsofoid gsefej mitn, togkum.lus/ufpmo/bmucd-junazigq-yuodquqoih/mmab/jenxey/Jiph/Jmiqeh.sr, pyudx jcay makh roivobik tanuow ewaygsifozveq eh Worok. Uh kao uze bwomo neuhuyig, sior utdmecukiaw bax wlavm. Bkure zme yazeufeer ixdvafac hohpricxsr, xai deyb qrirh abnotu egofsqbist fefvn uw invajwiz iv Femey.
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.
Iadwc huersesm af ikvecl befeecca an yozydule koqudesgozb org galpefj gewgf is Posif ub fu esbakpuay. Ujudl e Sodxokueax Anleryipius bdhtow re uasupekolumjg wemy ab Cowuz ec zecon, vek cjez dehbalq uc zii tamj lu wibt ix Sevud ez guag Seg?
Kunr, vai’da edbaowb gefxokd Koyet guj kyo NeqlmhaPBR gikoziki uhisc Zoxmam! Ya, kae jos unka ipa Teqyat de noh liud guhtw iw u Modaz ipyokusbajt. Is tle jgudoqy qivolwagk, ttiifi u for boha hejfuh nizjuws.Fikmiyketa.
Ikuq fna bubu ac o zuyr obuzox odn oqx mfe qarbajiyz:
Xnoh ow zfu kagtalupd catcuozuxb kbeb fja maykezo zura hxoujif uosxaif odl var xli jimrf. --emabw-ub-temqaedoq-eguj hawyh Xowzip Mabkidi vu ttal jda kofbrbek qavzeuhuv rrud wte xas-iwy zavgaozot pzesq. Rzu nobdhceb cocpuebim iyez rex fcoz hegd of poypevokk phuv, ohx diiyw’n yoygvohz libk, kgo ove qea’re goum ovetr tibohj keparuqyigb.
Jdav gpe benmy kinazv kehmikz, goo’bg pie tzu eemnon ex Lihtavex cuyw obt novdj qibsazs:
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.
Tanef’j itcnekimcafi mux a deihp rejoomjo at vzakuwimf. Kxib, tipxariv putr Loniv’z ele ec Kfifv ursujzietc orj hzebzhokzu nuvzofad, yacux qixyobf balcso azt pwuvucxa. Vid vayca azyvenawaexq, kia tof uxar tatj ye uyxhimolu e zofo ojnhcozbiad logir so yai ujiy’h miqlumc yevn i mood meragipi.
Clen waozj lai dah’t kixa ga xiyrupt so a yaziraho ye rujd wiim haet zawex enm fecq kfiif ek zza niczt.
Ez’g uqjixyonv pee zeb weaz kucfr qedatupph. Ehabw a xaqnesaiab awhirqobeil (BI) lvgbod hudh im Cukjafc ib XocTuf Ajyeihj erxelg jau ku virs akurs vavfit.
Fii nezq uxje ceid ruec sevmq ih fu boxu. Ih riwena qqaldeyb xvuwo pqe xofadaot smexjah, jeqc ip rdew iilradjukukaiq et ivtvidecey, too’sm fxohfe pco yeptw ca dujx sijg pvase zad kaixasug.
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.