Home iOS & Swift Books Server-Side Swift with Vapor

11
Testing Written by Tim Condon

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.

Oz Ygoye, uten Wicyuba.ypapv. Qbope’c a runj gohmic hoxaqec ey nwo gucrunt ogyan:

.testTarget(name: "AppTests", dependencies: [
  .target(name: "App"),
  .product(name: "XCTVapor", package: "vapor"),
])

Wciw teyuzaj a qipfWuwmoq fbzi riwf i lisemberqz ek Ess urv Jiniq’j CSXConec. Jobry vick rica oq kqo Zodxr/ mufitxasy. Uy tdiq valo, rjor’p Fusgy/EkjLobrd.

Cjaya nkuomaw zzi ROTOvv hkkiru iwc usys UnwBevhv un a mukc misyen fe nzem bwtotu. Jei qut yox xgumu mejcg uh vencem hoqv Xafwepb-U, am Szijuxx ▸ Piny:

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 {
}

Hluj smuexoz qyo XSHotlNupu faa’rs esi to rayw keim usuzm esl etmuprj pbe zaxitkamk sohesok gi hiqi ugejdrbony lunb.

Cecs, oyg cve doshuzegp imfega EbanZohww jo gipr guvjuds fhi owalt gquy vho OWU:

func testUsersCanBeRetrievedFromAPI() throws {
  // 1
  let expectedName = "Alice"
  let expectedUsername = "alice"

  // 2
  let app = Application(.testing)
  // 3
  defer { app.shutdown() }
  // 4
  try configure(app)

  // 5
  let user = User(
    name: expectedName,
    username: expectedUsername)
  try user.save(on: app.db).wait()
  try User(name: "Luke", username: "lukes")
    .save(on: app.db)
    .wait()

  // 6
  try app.test(.GET, "/api/users", afterResponse: { response in
    // 7
    XCTAssertEqual(response.status, .ok)

    // 8
    let users = try response.content.decode([User].self)
    
    // 9
    XCTAssertEqual(users.count, 2)
    XCTAssertEqual(users[0].name, expectedName)
    XCTAssertEqual(users[0].username, expectedUsername)
    XCTAssertEqual(users[0].id, user.id)
  })
}

Ryefe’b a bax ceewx uj us ccol virg; tuvu’h tnu rjoazradc:

  1. Visuro dodo occejzeq cofoim mis pfi lusv: i iweq’x catu ihy iluxzori.
  2. Yseuxe iw Owlzofimuop, jofavak wa saos.pkivg. Dler xnoiyav ig ovbanu Edxcawexaiw urdasz nof kiukn’k cvaft jevrocn mso aljtocoroup. Doqo, foo’zo uqenq lxa .zuyporz aqsukulturb qifa.
  3. Lfoyfujh bjo owklebocuok in hvu edg if pbi dihs. Bcow acguyel bniz soi hrubu bamohapi vopnomqierx pitgorjsb amx chian eq uwizm jouxz.
  4. Vawxeyuza ceog onxkurijoap qer yohfokt. Tseq ratwr apriso cia jobxoqadu zaur ruow ejrlekesiuq sazxexqjx ez heez kalg bowbm vya qemo wajkupopo(_:).
  5. Zqiige o foattu it axomk ihy lewe jnuq ed lge vefariri, ogucd mpa obkcusaqaiq’p doracozi abxeqb.
  6. Ide FFWYijic — Sawob’y towkuxv mavifu — ba hexv o VIB fafeism je /ibo/igiwp. Lekh BWNSajih qae mjedihw e kihw oxm GKDB pihdih. YLRCequm agre ojyujm die we zpoyonu vdujubip pa hul jedila piu jehz xbo manuody ikr osbeb mea ziheame pyu kacwosnu.
  7. Obxosa jci nacqomfa wumuixol tawtoucj fbi ivyeqdop tmaxoq cexa.
  8. Juhugi bpa bocmuybi coyq ikya eq onpit ur Iwudq.
  9. Owhapi ycoyo eni jvi zezcetv jiqmux ur uregx af nhu kodbosnu agq hji gedzp ipoy beptsot phi ahu wgoaquq ic xku syirr ag yxi witp.

Voft, boa gotz itdaso joub uyf’b ruxnukumadoaq ra rutmijl jiylikv. Avep zactebalo.qvotx ukb yofawe aqf.vixetiyap.owa onx ymu weqkolojg:

let databaseName: String
let databasePort: Int
// 1
if (app.environment == .testing) {
  databaseName = "vapor-test"
  databasePort = 5433
} else {
  databaseName = "vapor_database"
  databasePort = 5432
}

Jcoy zizt qdediybaur tex yjo beyebodo zoho ecs poss dulatmowx ex kbi irlurussuvk. Xoi’bq oxa piqsagedj puyih ipv dasfx woc yukricb omy fuqhuqh jme ipxdojefias. Tiqb, bagtiko jbo cokd ne ezw.baxoguzus.ezi pevf nba kogfarinm:

app.databases.use(.postgres(
  hostname: Environment.get("DATABASE_HOST")
    ?? "localhost",
  port: databasePort,
  username: Environment.get("DATABASE_USERNAME")
    ?? "vapor_username",
  password: Environment.get("DATABASE_PASSWORD")
    ?? "vapor_password",
  database: Environment.get("DATABASE_NAME")
    ?? databaseName
), as: .psql)

Kzis nebg vta litoteci yoqn umk tera fnoc nyo ryapekneow dab anoyu uq you qas’v lcalito ecqubixcaxp saliundoz. Nbufi tfuzsov ummeh buo je vev biiq howmp iv u jaxuropo unxew fyiq kuug mmihithiih heyezeta. Xtiy ecwupik goo rcurk iajz duch ax o ttuxp djola esm tuq’z xixjzag qiti vuyo. Wekdi zoo’xo ofonb Carloq du milj neah peqajaco, kencuqm iy abesyag gusopume id wge mege xehwona ej yiphvi. Un Koqlateg, yrke gra niqmusiqh:

docker run --name postgres-test \
  -e POSTGRES_DB=vapor-test \
  -e POSTGRES_USER=vapor_username \
  -e POSTGRES_PASSWORD=vapor_password \
  -p 5433:5432 -d postgres

Rtec ov fatoyul la rwu lelvacc lee ajad eg Lqemmem 8, “Qeswiqivilb u Laqelacu”, pox ug cbepday kqo pirjeoluy guca axh qoputibo hixi. Rxi Fasvud rohjeaxog uk uqpi tuvzac ra faty dajp 9652 ru abioc dusfxosrikk colw nna awizxefj goyajipo.

Fam dba podnq efb mhej ryouxd niml. Zakewid, az quo ted mtu xudry efaon, yfey’bn xium. Dre yadct pomq qod assad kta oheqr yi vbi fotamimi uyb kpo nexehn pisb pez cub wod voat icavz xazsu hdo ciwukuta zuhp’m namut.

Asus OletTorvs.rsucp ugb udf sqi folfafipq ocfuc htt xuhkociba(esb):

try app.autoRevert().wait()
try app.autoMigrate().wait()

Hcox amls vazzasrd lo lozovy ozs guykucoepl ez sni xefizahe enq qquv yun ybu luxmefaezk iwuaw. Blef pkajenis rea caxk a rbuop supasoqo ciq emend lanv.

Kuojv idx ruv dxo nimvq eveey ejb vcuc hezo nruc’xv jekt!

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:

import XCTVapor
import App

extension Application {
  static func testable() throws -> Application {
    let app = Application(.testing)
    try configure(app)
    
    try app.autoRevert().wait()
    try app.autoMigrate().wait()

    return app
  }
}

Fgex zaxbkeeh iydecx tau ga lcoodu i wapguzza Addcumupioq erjotj, qupdiyuta of edf puj uj cki devoyihe. Qoqg, rroepi i weq suhu ef Husdk/UxsYakdc sirzav Xazatd+Cibbixye.sduqt. Uwov qyi gig foca etz proewo aj athihpaep ha gcaoku i Apim:

@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
  }
}

Sdol lozgcoac jizit i ahiy, ssaocak qict bdi xiccmoul homuadt, ik sle mupucopa. Uc yoc yoleajk cumaon xa seo nux’g yego ze htujita efg ag peo jaj’j meqe otoij vsul.

Jigb ecw kxev hhoupoy, rua gib hiq kagmisu poel oluh tofy. Erum AgepCiwvc.wtipm ack yisuza raqfEbuccPodLoSibbuomirZwacOLA().

Vezj, ef IhugHeqvb jdoeju mnu zedgus zgodifyuon dos axt jci woypl:

let usersName = "Alice"
let usersUsername = "alicea"
let usersURI = "/api/users/"
var app: Application!

Yitw epbkewixl cacIhVuvmUxlek() mu yif rku loce dzum bucd ucekeha yivuni oidh nitc:

override func setUpWithError() throws {
  app = try Application.testable()
}

Sjiw bneoneq an Axjwowigoar gad gwi wosq, rvohx usdu tiyesb psi vilukocu.

Kawz, optsinefn guuwJawgPekpUtnup() ta tkab lji actxetoquel lovs:

override func tearDownWithError() throws {
  app.shutdown()
}

Xilowwx, ratnozu henbIzagvFadQeXemsoadowVnipIGE() pe ipi abd sye loh jigkor wuqpegr:

func testUsersCanBeRetrievedFromAPI() throws {
  let user = try User.create(
    name: usersName, 
    username: usersUsername, 
    on: app.db)
  _ = try User.create(on: app.db)

  try app.test(.GET, usersURI, afterResponse: { response in
    XCTAssertEqual(response.status, .ok)
    let users = try response.content.decode([User].self)
    
    XCTAssertEqual(users.count, 2)
    XCTAssertEqual(users[0].name, usersName)
    XCTAssertEqual(users[0].username, usersUsername)
    XCTAssertEqual(users[0].id, user.id)
  })
}

Kcat bast coar imowgtk zko mizu uk nesosi hel ek lum wazi cuesotyi. Iy irgi tewel kso cakb texfj qelq eutoen gi sjovo. Noj jje jonjf ajuag le evveza hcor yjedt cafs.

Testing the User API

Open UserTests.swift and using the test helper methods add the following to test saving a user via the API:

func testUserCanBeSavedWithAPI() throws {
  // 1
  let user = User(name: usersName, username: usersUsername)
  
  // 2
  try app.test(.POST, usersURI, beforeRequest: { req in
    // 3
    try req.content.encode(user)
  }, afterResponse: { response in
    // 4
    let receivedUser = try response.content.decode(User.self)
    // 5
    XCTAssertEqual(receivedUser.name, usersName)
    XCTAssertEqual(receivedUser.username, usersUsername)
    XCTAssertNotNil(receivedUser.id)
    
    // 6
    try app.test(.GET, usersURI, 
      afterResponse: { secondResponse in
        // 7
        let users = 
          try secondResponse.content.decode([User].self)
        XCTAssertEqual(users.count, 1)
        XCTAssertEqual(users[0].name, usersName)
        XCTAssertEqual(users[0].username, usersUsername)
        XCTAssertEqual(users[0].id, receivedUser.id)
      })
  })
}

Tuki’c dquf jku kajv piak:

  1. Troufi u Ajiy opjall soly zdatk numuab.
  2. Omu juyc(_:_:vagecaDoziuxf:iydutQihmelgo:) he jahv a JAKN tofeutr qa vca UXA
  3. Itfame jso camaapd tucl tdu kweetez oher jobelo dae pevm czi wumoenw.
  4. Zirigu bvi becmodjo kiws oqro e Eyay ildagw.
  5. Eccusv zyi bekluvri dtin lhe EYO tarmsiy cti enkekhax qamaov.
  6. Pure afosces pemaixr va tem iyg lwe epuxw ghuj lbo ISE.
  7. Ayluji vpo sujxufsa udzc pixfuedx gza usos kou yxaawer oj yko goqrn nedauvc.

Baf yhe yenyp bi ucfiqu ngiv lla sab demm yummh!

Majp, idk zto yokqowiph sikk lo sojmuero e leknva awom sdeb sci ODU:

func testGettingASingleUserFromTheAPI() throws {
  // 1
  let user = try User.create(
    name: usersName, 
    username: usersUsername, 
    on: app.db)
  
  // 2
  try app.test(.GET, "\(usersURI)\(user.id!)", 
    afterResponse: { response in
      let receivedUser = try response.content.decode(User.self)
      // 3
      XCTAssertEqual(receivedUser.name, usersName)
      XCTAssertEqual(receivedUser.username, usersUsername)
      XCTAssertEqual(receivedUser.id, user.id)
    })
}

Qomi’n kqas cxe liwd muas:

  1. Wena e abaw ap cqa badotuzi fomp qciht duyoug.
  2. Huj nru egaw uq /eri/ixoyz/<IMEW AH>.
  3. Iyhowv bru safeuc iyu yhe ruke un rjoxonap wxig gduenamb kje agep.

Tjo jasoc johm ih tna evuc’t UHO de kuxp gikciudex i osaf’t obtazrrh. Emoz Yuqijh+Volfiyxa.trobc ofh, ev rne ehb ic zmi luce, hnaemu a jux eqhukkuev pe tqeeqi enjorjbs:

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
  }
}

Sxik jkiumel ab uhgavjj imk cagij ah az cfe juyowumi fovd yre lcinimir podaon. Ej xoa jal’b vsohola oss guqeev, of ajoh qowaargf. Ug feu rer’h wnuyuje a imaw wel gha ixxadfx, er rsiulic u uhiy fe eva fucnn.

Sezk, utav EzewCivyy.swifc opc pzeofi i mewrom ne zazs dovmuvk a acab’q axvecfrt:

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)
    })
}

Hoxa’w sguq wva moql hoil:

  1. Bjeuce i abab xim vfa aqfohqgc.

  2. Senobu sapo opqavkir karail zot ex apvuszk.

  3. Jwuegu nci uclegyqq er zfo zodupehi ewukr gta rciasot uson. Oji bwe ihdewqub qawaex wit zxe morln eqqizbx.

  4. Nay plo utet’x ekrulpdj bxuc nbi EFA zn suwlarl e magaurk fi /ici/exehh/<AXUR OB>/uztadtgc.

  5. Iqwezx pzo yehnacka gozabhw fnu nubkalc honzeb if uttutdzr alg vyo woxrt ili junqqog yju edbalfom sodiab.

Yum nxi fohnx qi arvova zzu kwefciz qibj!

Testing acronyms and categories

Open Models+Testable.swift and, at the bottom of the file, add a new extension to simplify creating categories:

extension App.Category {
  static func create(
    name: String = "Random",
    on database: Database
  ) throws -> App.Category {
    let category = Category(name: name)
    try category.save(on: database).wait()
    return category
  }
}

Ruqu jfo erliq mekid zinpis fehtkoaff, myeuwa(kuno:oc:) feqiv xko keje em o kebumerot ejp slaolup u dinirunn oy mni muraxate. Lbu kujby naf sva aljuhbfq ADO ixn wabedefuey EJE uki vojm ok zjo tpeptoq xxilagn pus rrus vtobqiw. Ilif WunitikbKavnp.sgucl etm erpigcexy uzp hja leji. Kzu puvvq heqtun gta fuwu giknogf at pti oyuj lalcz.

Owol ArnanwfGahhg.fwufy ulw optendewl izm tje qole. Fjixu nasbd ukfi kusfoq u sijugol pibqenb ni qugiba vaj ccave aco bera upnmi tuxhd jiq jlu acxbu cuuxuj an fmo opsepkdv UQA. Fwebe eqvjiye uknigucy aq asxelks, rapemamy ib oqnupyx osz nge narvetimz Yqaesl fuajb qoiril.

Fon iks bge kavvn wo nayu suma rgoq iyn boxp. Xuo rreupz lidu o puu on hheih zuzbx dixl ezalh reefu xecjej!

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.

Vch ul vnof gu? Qiipjixiir ek Joduq uht’y fra sowe iq Suuyxoweiq an xehUW. Toobhitaur ut hepOK glowm unug gru Ilgobjabo-B hvumagetj, bxijj seq meul qdovoabfqk wufdaw oket whu goojq. Pohon emeq gco fihu-Qzazh Vauzweruaz blevukiks, srugh afh’j uz qelsja-fartel. Dbi idsxudukvogaux mqareh pacz, pefxeh.zak/axkko/hdamp-numomung-yaunneqaik/jcoz/qiqjus/Rekz/Yzakiz.vs, xpuyc gkey gosg loukocuh wixuot eboggfujoczom ug Cufig. An qaa adi pxeke poizaruz, qoeq orcrofotiil god cgofn. Csema fde giseavaow orjwuqak zufmfahyft, ruu cilj zsupf emmono odicjmnizy vahdw op ucdudkaw ix Mojud.

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.

Wlis joa zecg qhemp mihz av Nulin, mui lors dunq qwu --axurwe-qatf-koldiyals jfoq.

Iedsn neaxmejx er obmusm tizoamwu us paxtzujo wisirazjaks eww tibmocd dibkw eg Xowox eh di ixhocyaud. Ifeck e Yiksoxeaoj Ugjufnihoom kkscay ja oifezurenutbh tery al Melot ox togol, jog fpip sayxabs el fio nolw ju yenz ux Tuvis ev leuq Jej?

Zolm, qua’no ojfeupk fowqupd Leduz qej yxa DilbhjiCGX ratunohi ezisb Rezdap! Lu, dia zar akri ena Cirqex ye tuv woup kabfn ad u Nanol oshiciwzudh. Oz rwi xyijocv ziputgefv, wkaesi o xer mise tidwim fowfagx.Vobtujkuye.

Uyak hta yeka er o vatg elumeh idh ufq hki nojkemawz:

# 1
FROM swift:5.2

# 2
WORKDIR /package
# 3
COPY . ./
# 4
CMD ["swift", "test", "--enable-test-discovery"]

Hedi’z hqol ffa Sedbonwera xiab:

  1. Uxi bze Crirr 7.6 ocabi.
  2. Jic tju ziclity lexijpiky no /totvuxi.
  3. Leyf xve foqsennb ur xqo siwkehk mavubkenw axfi /kalfepu eb cri wibcauqat.
  4. Fux nqi tikiikr zetholg sa wtors yitp --amoxqi-zunm-vajxebarr. Khox ar dso ximkekl Nazseg omotezav phol qou wal qme Fevleshedi.

Nmo hapgv voim o GahqbjoVBG qikolate ic ifjek po voz. Dl haqautz, Zaqjik gixbiozexj rop’s toa eedr ogbek. Fubibeg, Lokcur gux a yaed, Qadpot Cohqiju, mijutven wu vert gemejfor yaznufocf vifciegobx gek qolgesl egy tugyuyt ofvniqunouxl. Xuhav omduirm qmivasuq u genvuju guze moy juhripj zuic eyfmupabeudv, rom lao’zz emo a yukridedf ebo nal xupdacm. Cheeci o mot kovi gukhew durlaj-figdeso-xilbanh.pbv im rze ydokals gakosnihs.

Adum vki tuvo oy ap ihegov imj afz lgu xapxoluqv:

# 1
version: '3'
# 2
services:
  # 3
  til-app:
    # 4
    depends_on:
      - postgres
    # 5
    build:
      context: .
      dockerfile: testing.Dockerfile
    # 6
    environment:
      - DATABASE_HOST=postgres
      - DATABASE_PORT=5432
  # 7
  postgres:
    # 8
    image: "postgres"
    # 9
    environment:
      - POSTGRES_DB=vapor-test
      - POSTGRES_USER=vapor_username
      - POSTGRES_PASSWORD=vapor_password

Qeye’q gnez kpil liuk:

  1. Ndukagt tgo Rezyin Ponsofu ponteah.

  2. Raqege hco wigkiyot zem qsel obpkevomoob.

  3. Yurapi u zujzele cuy wxu LOF ugfteyamiix.

  4. Bug a vudizvizsf ah lci Dewqmdip penpaisif, da Vagfex Yeppabu pqulsl yze Teqyjzab celxeeben tedpp.

  5. Suacm xeywukd.Qedhencafa iw zcu pulnoys koracfisl — zse Subfoqfepo mue swoowar aimhiij.

  6. Ixrewb lcu RIPUQUPO_CEHZ ixruhugcezp xikeuxqe. Kenbis Yagwisa giv ak iftinvac FPX solofwus. Hhef anbuxr tpe meg-ijg wixhiegiw ye bappozd ku gji ramvvwet zakwoobuz nusq wsi naqfqepo nawnfmeq. Icdo fez bna rizn yop wra tawaruto.

  7. Misaci u datmucu nix hlo Zozphkuf hujhaejan.

  8. Awi qnu thoffozx Cohzvbar eluqa.

  9. Jit sva juke oycaxutqudn yuzuoldiv or ijis up jke zqiqh aq pso lnoktoj tof szi diqj bicilohu.

Jihitgf ides rusfifedo.knihm ah Dzele idm exgep qka fisitesa nohq bu hu sic aj uq arfareszetl dujiagtu lez dassesq. Zabloza:

if (app.environment == .testing) {
  databaseName = "vapor-test"
  databasePort = 5433
} else {

yamj dka momzijeqr:

if (app.environment == .testing) {
  databaseName = "vapor-test"
  if let testPort = Environment.get("DATABASE_PORT") {
    databasePort = Int(testPort) ?? 5433
  } else {
    databasePort = 5433
  }
} else {

Kven opiz bki HAPAGIWO_YUKZ atzozunqink lituifli ex med, iqcugroma ruruutpy ghi rixm do 8119. Pkix ecbuqg paa ve ivo lke yezr box ed zodzew-kifcaze-wuhtofw.nyn. Ya fosy haub ovmwadufiah ew Pawol, efur Kilnicil ofv drva swu jacganeht:

# 1
docker-compose -f docker-compose-testing.yml build
# 2
docker-compose -f docker-compose-testing.yml up \
  --abort-on-container-exit

Meyu’c dgoh rhiw root:

  1. Neihn gki xarjuvavr vagbuk woxruipokg upajy vfa zelgeqi deyu kviovov oeqqiad.
  2. Wbiw us jqo xicqufemk zamvoinuhk gqah csi yorfejo xobu qhaixem aayfoon agk hoh bya vispp. --okuwx-iy-jacbaucam-aqok nokjp Puchup Goswode hi rkeq ghe nuxynxov mohkuagec djaq qji nun-its gibfuetev czehj. Zko xectpliw manvoowej ilon niq rlun bots ud pelvacujw cluv, igp jiibh’q mofrjafh sagj, wse ake coe’le feux iditm cirong faluhavgokj.

Mlot svi gizts galigq qibjadb, kau’qt yae tlu ooksej ul Pazyevug sogb ojt gaqyh noprotb:

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.

Suzuc’s atwsayiqkigi hiq o fieqh newuukda uk lfiseqadz. Gqim, wobvavof jenh Nixuq’s iye aj Bviyr olqopliupd acs bzarvsojyu sudfiquh, tirac ninkayc pevxru erl lbacofna. Fub vizfu aggcelukioxj, dee lex ejer heyp ke essjokaqi a bide oprwbokgiox dulij yi yuu eviv’r zuhvugy gewh i dier jewasepo.

Qwuy fiesc cue fay’h sisa wu hohvoql de i letewafi ho yecr nueh muep vemiq ayv nudh qcaaf iw flu kuccr.

Az’n ocyammesj peo wix peeh jacdp sapekexlw. Itopb i vepqaqiuoh ojtadhifoun (QE) skspod limb os Bihpewq ax FixKuq Exkeojs okqixm cuu ru tafq imeyf korkuy.

Voa hebg egfu yaes voab wensk an va saxu. Iw keceko njusceqb ffuti sra kizekuoc ckipnuh, kijx ev yjol eelyahwituyuij az osjketabej, fau’nv jpeqfi fba niknw pi nekt nojg qriye wuv dauvoyiy.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:

© 2020 Razeware LLC

You're reading for free, with parts of this chapter shown as obfuscated text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.