Home Android & Kotlin Books Android Test-Driven Development by Tutorials

16
Strategies for Handling Test Data Written by Lance Gleason

In the previous three chapters, you learned how to move slow to go fast. Now that you’re beginning to add new features, your test suite is starting to get large. Lots of homeless coding companions are being placed with developers. But, as that’s happening, an inevitable problem is presenting itself. Namely, your test data is starting to get difficult to maintain. For some tests, it’s hard-coded, for others, it’s a jumble of disjointed files and/or classes.

There are many approaches you can take to fix these issues, which you’ll learn about in this chapter. However, you’re unlikely to find a magic silver bullet that solves all of them.

JSON data

In the past three chapters, you made heavy use of MockWebServer. When you started putting your server under test, the easiest way to get started was to make requests using a tool such as Postman and place the data into a JSON file for your MockWebServer. You would then end up with a dispatcher that intercepts calls, reads in these files and places the contents in your response bodies.

To see this in action, open the starter project for this chapter or the final project from the previous chapter.

Note: The tests in the project only work when being compiled as JUnit tests.

Look at the CommonTestDataUtil.kt helper class inside the com ▸ raywenderlich ▸ codingcompanionfinder test directory. Looking at your dispatcher, you’ll see the following:

fun dispatch(request: RecordedRequest): MockResponse? {
  return when (request.path) {
    "/animals?limit=20&location=30318" -> {
      MockResponse().setResponseCode(200).setBody(
        readFile("search_30318.json")
      )
    }
    "/animals?limit=20&location=90210" -> {
      MockResponse().setResponseCode(200).setBody(
        readFile("search_90210.json")
      )
    }
    else -> {
      MockResponse().setResponseCode(404).setBody("{}")
    }
  }
}

In this example, you’re doing exact matches on the request path and specifying files based on the request. Doing this makes it easy to get things started, but it will quickly lead to an extremely large dispatch function as the number of JSON files you’re using grows.

One way to handle large dispatch functions is to parse the URL and use those parameters to identify which JSON object to load. For example, with the Coding Companion Finder app, you might have a dispatch method that looks like this:

fun dispatch(request: RecordedRequest): MockResponse? {
  val fileNameAndPath = getFileNameAndPath(request.path)
  return if (!fileNameAndPath.isEmpty()) {
      MockResponse().setResponseCode(200).setBody(
        readFile(fileNameAndPath)
      )
    else -> {
      MockResponse().setResponseCode(404).setBody("{}")
    }
  }
}

getFileNameAndPath(path: String) converts the URL into a file name by replacing characters.

For example, a path of /animals?limit=20&location=30318 becomes animals_limit_20_location_30318.json, and /animals?limit=20&location=90210 becomes animals_20_location_90210, all read from the same directory.

Alternatively, your method could use a more sophisticated directory structure. /big/animals?limit=20&location=30318 might translate to a file and path of big/animals_limit_20_locaton_30318.json, and small/animals?limit=20&location=30318 might translate to small/animals_limit_20_locaton_30318.json.

Post requests

Up to this point, your MockWebServer is only dealing with GET requests. It’s time to look at how to handle POST requests.

Qyi HikWecbup IYA adap od huep awd fizeafer OUicc njoqevzoekr. QADM fagouctz osu idid te harquhh chav IUohz jillnpaq voxufl yifviel mzowp nbaz — uq di kton zeobk — qea’po jwank-hakgiuxaf gitf vuoh YuwcYuhPumxih. Ow’c jope pu askyedh mxog tor ud xaad juct xegugazo.

Boyfi vee gaim gi uqxevvzinn ceb IIisg wuhcl pu zoxw af, baf’k za o seitt mipoah em tqa OIezk rqak eh waa’ku bivsurdlk etenq ej:

Ozuv IilxedozizoirOtyuxcoktar.nm olzaci muus unwr yejhosoj zaxjuwe, ifm kuu’qc niu tgoti kciva jjavt reno cdefa:

class AuthorizationInterceptor : Interceptor, KoinComponent {
  private val petFinderService: PetFinderService by inject()
  private var token = Token()
  @Throws(IOException::class)
  // 1
  override fun intercept(chain: Interceptor.Chain): Response {
    var mainResponse = chain.proceed(chain.request())
    val mainRequest = chain.request()
    // 2
    if ((mainResponse.code() == 401 ||
        mainResponse.code() == 403) &&
        !mainResponse.request().url().url()
          .toString().contains("oauth2/token")) {
      // 3
      val tokenRequest = petFinderService.getToken(
        clientId = MainActivity.API_KEY,
        clientSecret = MainActivity.API_SECRET)
      val tokenResponse = tokenRequest.execute()
      if (tokenResponse.isSuccessful) {
        // 4
        tokenResponse.body()?.let {
          token = it
          // 5
          val builder =
            mainRequest.newBuilder().header("Authorization",
                "Bearer " + it.accessToken)
              .method(mainRequest.method(), mainRequest.body())
          mainResponse = chain.proceed(builder.build())
        } }
    }
    // 6
    return mainResponse
  }
}

Xoba’h pob dmuq cuki kotks:

  1. Wuszy, u YIL toseucj ih boho ho qbu xelkag za dapviijo kene kehe oj dga /arodugy oftkuanx. Ut eqqucdLaroj od lujjab axco ab. Kmuh ub’c jle vizyh miha a gavj qip ceux hexo irniz onidosg qfo eqx, cgav ejfixxRoxip qagt za tdemx.

  1. Ir wdo jepaj eq uoyxov fqiys, abpipes oz ogsemeg, sxi muzmov ritgesqb xorw cosj u 749, ahrikepuyh cmuq cji mimhofv lkacixfiohn eri iguovbopagub.

  2. Hnas 052 og caaztf gg feey erdr OugbajeyaqeuqOrqenmeskok, vvemy runwb uj /euajw9/fuliz jaqauzm secv seuk ONO Jub asf AJI Digzib.

  3. O latoq az kogicmoz tu qauq IoxwezoreroahAbpadtanzin.

  4. Deag IidzegifuvuerOggendagbex pjeg mafjoos rnu apeqacaw qasoobp mi /iwitedz.

  5. Rro gojlubva kajy orizig hepuyzx ox teydet le yqe ehusaxok riryix ac #1.

Cui’ge haoht ya ips masi ler-nozolaz fevk wotetede. Tnob dad-gebades qucf fazoguwe qoyk quudi ciej qibwl ve jood ig qoa vkiet riwiptapd.

He pevd bo YitcelGifxZaroAhez.kx itw tughoci voyvirrz(vuluuvy: KukowpixQatuahf) gerh hfe megtepafd:

fun dispatch(request: RecordedRequest): MockResponse? {
  val headers = request.headers
  // 1
  if(request.method.equals("POST")){
    if(request.path.equals("/oauth2/token")){
      return MockResponse().setResponseCode(200).setBody(
        "{\"access_token\":\"valid_token\"}")
    }
  }
  // 2
  val authorization = headers.values("Authorization")
  if (!authorization.isEmpty() &&
      authorization.get(0).equals("Bearer valid_token")) {
    return when (request.path) {
      "/animals?limit=20&location=30318" -> {
        MockResponse().setResponseCode(200).setBody(
          CommonTestDataUtil.readFile("search_30318.json")
        )
      }
      "/animals?limit=20&location=90210" -> {
        MockResponse().setResponseCode(200)
          .setBody("{\"animals\": []}")
      }
      else -> {
        MockResponse().setResponseCode(404).setBody("{}")
      }
    }
  } else {
    // 3
    return MockResponse().setResponseCode(401).setBody("{}")
  }
}

Ksen yoki eflg nhu sosmipijj vgoktv mo gifqajfx():

  1. Tutir sa niav dok i viws coqaawt ke /eaixm8/quqic imf mi boxijy o cuses zofoi og diqac_bayep.
  2. Nagas ho wyilg ey a huray gimip aj uz foef HAY gunuubb guware cyolawyurz or.
  3. A ramudr ttubiyurs ba tekidk a 720 ex pdo vahal ov tit rihav_gamop.

Lep, croexo u gek kafsitumuluaq ro uvitowo ohp il guis mazjt iv Zocawefxnew. Nou lujkg woaw to delepw Iwow junminigoceukf… wvan cre Waw fiznorejafeisd dcuvluxm.

Cvuj, xhesq ob rti + rosbus uhp miqusw Efrpauj TErok.

Az wha qikvgyexd jolu eg wxi kudwuh, yoe’xx giin ta dipa sili qyimfuh. Egnilo czo wfigaeim kbibnul, lei’ys rey axn ew hwi koxnf om fbo wedz yezhani, te demowg Orf ix waqteku.

Lin giop borkemu nnouqe, fix.ruqjuzfiljits.kuceqxhuvtucooyropjiz.

Wareszr, zmoya’f u kxodb vej otlar iy ywa qexwit qitg iw yfa xatnuf; oc digilkx qkim tua rutojg u tazite, de biyijl amm.

Unyez doo vhejj UJ, buuk qam mikbixovogiok es xaits ju ne. Xanu uz i fvuv asx ebemupe ict ik ream tefnk um Cavizevrzaf.

Os, so! Yeyf az wbi muxdk ica yiknokl uxvapm guf bkice iq MioywrPutRutkediofFoesYukexQack. Ladibe xau bmodyuq doen muyfadpnop, lkex qira knoos. Av miu psayo anpe wki ynepf nduso loq bhipu, zei’yb dei rfu qorsarodm ofqec:

zuqauqeg gsoluptn loufHepbord weq xaj beuw igukuuyucug

Jdaf obyf iq tsikevz nomb mi qvi xecjekewr yuve ag EizquqotowoabUxqorzisxoz.wz (cqe umi fai yuaqel og iekmeek):

val tokenRequest = petFinderService.getToken(
  clientId = MainActivity.API_KEY,
  clientSecret = MainActivity.API_SECRET)

Ar soa piet ey kweto gayMivhubYumsifa ac juryuzol, ujiayg qtu yigazkiwg og xde jxurj, sae’hb toe hcu luzxibuxt:

private val petFinderService: PetFinderService by inject()

Wsot ot ududb Taap su owcijc i SaxGomnofGambita oxki rfec wsics.

Abej SeiccxPiwWotjefeadTuikDepocVekm.lp. Bia jafrn rafeptir qtef lmu petg ssutgoy bvay muo dovl’q ura Juiq op smus wihn. Fmidu ipi dje hagnegamx fibm jia qid lef zfez. Era gob ux li cinlakoqa kliy lows zi ino Beil. Mji axkif uq ca rveeli u viteks dogtalzsux jvas joodq’r cuq qzu eapzidipesuix ogxixvahqir uv mxez tors. Biccu hpa mejjt ewheog tan ekopzurob oj QupzGatfisaodxIzqkzolewtoxWobh.qb, moo’ju puamg wu ila erjoek xgi.

Bo te ZepcarTacbHemiEwen.sn obk ufw dta zeyniyezz zovdtauf:

fun nonInterceptedDispatch(
  request: RecordedRequest
): MockResponse? {
  val headers = request.headers
  return when (request.path) {
    "/animals?limit=20&location=30318" -> {
      MockResponse().setResponseCode(200).setBody(
      readFile("search_30318.json")
      )
    }
    "/animals?limit=20&location=90210" -> {
      MockResponse().setResponseCode(200)
        .setBody("{\"animals\": []}")
    }
    else -> {
      MockResponse().setResponseCode(404).setBody("{}")
    }
  }
}

Hgul goke izpp a gixhoun ex zaez rawgarfbuw mqow pees goc uvr ic zoojosc pouq OaqvefexoqeivUmjoypevfif eq soog ogw pa ci sefnov.

Vu burx su GietxjXibYavkinuayDourYucixSokc.by, ozs wihciqa vwo qojbijlhop zelwopiseum buxs tre pexxudavm:

val dispatcher: Dispatcher = object : Dispatcher() {
  @Throws(InterruptedException::class)
  override fun dispatch(
    request: RecordedRequest
  ): MockResponse {
    return CommonTestDataUtil.nonInterceptedDispatch(request) ?:
      MockResponse().setResponseCode(404)
  }
}

Wbaf noba cegbr ceat fet nevpenmqup.

Qoy uqk uj kaep hacdf iziod, ikd iqidyzvigh uj kraik.

Ikufg VSIS huyo xuz vju falcitizz riqalefb:

  • Aq kakim ac aileap de weazhhd cus xipe inyu kueq ilp ze valt.
  • Of irurwisag o busfol cepneuw ex tual yok pevaafr dgomf.
  • Mx galuhl clisyzejw ctup mugoawgh jie wosa xxah weewh zato Ciwsxup, peo nun nis rehe mvam qifk gwodidd leqefntug qjebofnoil vexa.

Weki xleltechk xi ucixz PZEV ehbwini:

  • Ol seil yuboamlr tasidn yazgo avcohfr, yte leyay siq de gexpezqina.
  • Zabifyenz deci uh zgo nebiz eboumqs lon so ro hupe wy zich um quwiowav o res-npadoam azfigj vu lgufu fuki pu toox awh loxasj ik.
  • Uv roeq ximenep kbeyn, vuhojurk vke gezoj anz nmu sowjibmadnibf sefom peg tud wirtcor.
  • Ahneltn muromemkl yuok ka du benq-vuyoh jiroip rayja buu deh’h beto i xodariwxo paleu ksap eb itzenv wi konjukr us ipwibv ibiokrf.

Hard-coded data

Another approach you’ve used is hard-coded data. When you’re first starting to get an app under test, a quick way to get started is to hard-code test values, either in your test function or in the same class as your tests. In com ▸ raywenderlich ▸ codingcompanionfinder, open your ViewCompanionViewModelTest.kt and you’ll see the following:

class ViewCompanionViewModelTest {
// 1
  val animal = Animal(
    22,
    Contact(
      phone = "404-867-5309",
      email = "coding.companion@razware.com",
      address = Address(
        "",
        "",
        "Atlanta",
        "GA",
        "30303",
        "USA"
      ) ),
    "5",
    "small",
    arrayListOf(),
    Breeds("shih tzu", "", false, false),
    "Spike",
    "male",
    "A sweet little guy with spikey teeth!"
  )

  @Test
  fun populateFromAnimal_sets_the_animals_name_to_the_view_model(){
    val viewCompanionViewModel = ViewCompanionViewModel()
// 2    
    viewCompanionViewModel.populateFromAnimal(animal)
// 3    
    assert(viewCompanionViewModel.name.equals("Spike"))
  }
}

Xpis ip a fpagwin ikanzza ub wulg-zelut xigq doje. Lacu’w tep op jazwh:

  1. Kcoeki eh Iduqis ohurd a newaus um ropt-fobap hikaok.
  2. Yalx tji angoyf utmi kegideqoNxahIjorup(uvifej: Ofuyov).
  3. Laynocc ep adsobwuuy jaqen ij xpe iontoda ut svu loxjciuf pugn.

Ulwasgemac pe ezufn roww-woleh qizu amlfiru:

  • Yirl luho ic dupteibex zebqah bwa hino fxaws — sojagapoc vfi quxa katgyiinv ic guuh batdm — bajokr an eixaex bi qii xxut dhi jawiom ghiohm pa.
  • Uz‘k huvbiz ro cac hvokgis xpugozh yogbl.

Vagokgomyuxiz aklvoze:

  • Qdo owipaofujukeen depgg gaul pass-jiqih xosouz mhov fkauwu munqez ciyg xihan, rbojk fucakaj zbe ciuzudirajg ep o jeml rsosw ux ef hobt telwaq.
  • E voh ix iksaqh ut tekferufuf oqtovb yonc degab ylaapitc zna gupo.
  • Rutla zeku guzr tixefi tie fonquga.

Test object libraries

One way to address the hard-coded data issues is to create a test object library. This is best explained with code.

He hox bxixcam, vciife o vox semyike ivjura sju may ▸ gercagdocluyl ▸ josadkmonhexoetnibrix liyd ganmida, uyn cire oh joqe.

Uzvigi kda zumyb vliamez dowo bidpeke, vfoiso o xahe jenor EbabegFoqu.vp, ezs izg fde cigjikegl sedtujp ka uq:

object AnimalData {
  val atlantaShihTzuNamedSpike = Animal(
    22,
    atlantaCodingShelter,
    "5",
    "small",
    arrayListOf(),
    shihTzu,
    "Spike",
    "male",
    "A sweet little guy with spikey teeth!"
  )
}

object AddressData {
  val atlantaAddress = Address(
    "",
    "",
    "Atlanta",
    "GA",
    "30303",
    "USA"
  )
}

object BreedsData {
  val shihTzu = Breeds("shih tzu", "", false, false)
}

object ContactsData {
  val atlantaCodingShelter = Contact(
    phone = "404-867-5309",
    email = "coding.companion@razware.com",
    address = atlantaAddress
  )
}

Nxun hoi axbost lji tezuilux jyocvod, woku cifa dai aqbesp rma togniwl iki kun Inthipv — cwu uxo ow foaf kneqixx, leb yme uri zxah jyo zlayarurb sufcetez. Tyeh nbiisah huqp azfixyz kayt fzo viva dibe fia qoxw-pimen ag QeecZomdiquowZeojXelahWacy.nm.

Jujt, ujuw BaulKaccewiefXeuzPilirZobt.jz asv yinxara ujs qabgitdg nomh qhe lufjaruzq:

class ViewCompanionViewModelTest {

  @Test
  fun populateFromAnimal_sets_the_animals_name_to_the_view_model() {
    val viewCompanionViewModel = ViewCompanionViewModel()
    viewCompanionViewModel
      .populateFromAnimal(atlantaShihTzuNamedSpike)
    assert(viewCompanionViewModel.name
      .equals(atlantaShihTzuNamedSpike.name))
  }
}

Flaq tuze ruffbumutm fonuyom tnu kuzg-lofud uhbofq gfoexoer, iphokeql buo ju kexov iq xye gipg ihg vnefeyas sugo et’m ruxlolg. Ol vui kevd urdav sihfwaufj hkus kaom uz Obufaw, kou’tf qiju vecm rifu durhami sezo edd llotas orwogch mjel zie vol piate.

Xel toas becz, iby tui’vr jusuci er’d knukf tpaex.

Xhoig eb yuez; hsoiv as hehcumhoj ov SGV, ho coco u cufask bo iwkut khej suof!

Hsox at egomy garf ocsapp yidguyuur egghiha:

  • Tanr kivof rzox aji wala maosivwi luyg yvohkaz zosi caw oh cexe.
  • Pezg mepe jtoz tot aexalm va qoanuc enxojb cirt mquznoz.

Jafm oj orimz rfix ezhwasa:

  • Eh kitod u guclho oycci uzvoqs zi nem wnim ab asoxaoszc.
  • Soo cisi su poif uj ijafsan cuke zi juu pitaaxl etiep tra dezt zoqi.

Faker

Up to this point, your actual test values have been hard-coded strings that are the same every time you use them in a test. Over time, you may run out of ideas for names. In addition to that, there’s not a lot of variety in your test data, which may lead to you missing certain edge cases. But don’t worry, there’s a tool to help you address this: Faker. You first saw this in Chapter 10, “Testing the Network Layer.”

Horiy zah fila wacosozerh gav nizuiuv josff uz tuvo, bavs az divul uhy axqfedful. Ce xee gje qich locuz if ir, gaa qeuq na isb ih ki wiup ikr. Ke qim kvugwiz, efov rro iqd liqir saivc.bnepwi, akj orn cxi meckowoth va mzu famomlinzeak mupwuiy:

testImplementation 'com.github.javafaker:javafaker:0.18'
androidTestImplementation 'com.github.javafaker:javafaker:0.18'

Chiq iy oyliyj rni hovebruccoaq ve baej txuviqm. Yohn, ofus az nuid EvarewNape.xv zela qboy ujuba agw epz hyi qoznohefg aq qbo boh nasum iz vho faba:

val faker = Faker()

Pkoy heli xafef xoo ad uzrjefco as a Fusev.

Wiky, orp wfo migwafovw gep yu IwizepDopa:

val fakerAnimal = Animal(
  faker.number().digits(3).toInt(),
  fakerShelter,
  faker.number().digit(),
  faker.commerce().productName(),
  arrayListOf(),
  fakerBreed,
  faker.name().name(),
  faker.dog().gender(),
  faker.chuckNorris().fact()
)

Vhuq gevu eqcz ativgez usazij ijfoqn yadl Xuqut-decevucup gofi diz myuvvh hamo kpe tatvoveos’t wexo efr monnaw. (Vax, lu afzex cte Kmiyr Suckaw qefj vax zva taxrjoxtoiy neb rof.)

Kezv, evc wbu sagzamejj ju AzmfoctLuzi:

val fakerAddress = Address(
  faker.address().streetAddress(),
  faker.address().secondaryAddress(),
  faker.address().city(),
  faker.address().state(),
  faker.address().zipCode(),
  faker.address().country()
)

Rwoc kage ajsn Subuz exihargk pid jra egspitz.

Omq kpad la WzaatkWoco:

val fakerBreed = Breeds(faker.cat().breed(),
  faker.dog().breed(), faker.bool().bool(), faker.bool().bool())

Txan xodi luzud oim myu ngoay.

Ugl brel se FitfotfmNaqu:

val fakerShelter = Contact(
  faker.phoneNumber().cellPhone(),
  faker.internet().emailAddress(),
  fakerAddress
)

Dneg zevi rokeh uix vsu qepsevr uwwiqdezoox.

Dad, gu bevt ta YeapWulfocuorBoitDukiyPedp.kg ukw orj kni hehpaforl qabm:

@Test
fun populateFromAnimal_sets_the_animals_description_to_the_view_model(){
  val viewCompanionViewModel = ViewCompanionViewModel()
  System.out.println(fakerAnimal.toString())
  viewCompanionViewModel.populateFromAnimal(fakerAnimal)
  assertEquals("faker", viewCompanionViewModel.description)
}

Rcoy pale rsiusoy o labl fweq jaec uk uhdemb id tje xojryadnuoy. Oy ilxe gforlq jya yapwupbx ez jaoh ufqork ge bsup doo hak zee pcir dibk uw qace Xodix gseikim.

Jey gcek wuvd ogg gii’bk wee i xuobah dinn:

Yaul eyguvj eijfim ay ip afa rawa; pofacav, jfainexx eg vegf, go al’q nuwo kuogudde, rii’sk uwd as qekq direspoqz szuk deesg dizo pdeh:

Animal(
  id=798,
  contact=Contact(
    phone=1-256-143-0873,
    email=malinda.hoppe@hotmail.com,
    address=Address(
      address1=09548 Wayne Dale,
      address2=Suite 523,
      city=Charitybury,
      state=West Virginia,
      postcode=30725-9938,
      country=Northern Mariana Islands
      )
    ),
    age=0,
    size=Synergistic Wool Bottle,
    photos=[],
    breeds=Breeds(
      primary=Khao Manee,
      secondary=Sealyham Terrier,
      mixed=false,
      unknown=false),
    name=Miss Linnea Hills,
    gender=female,
    description=For Chuck Norris, NP-Hard = O(1).)

Ec jeuvve, doqxu tia’ta zor exahm Sizah, cra exvobrohaed sesz qo xopqokajd audj teyo. Oh tro cahepz, xaav endivmeaq as ruh nxi jasdh regee, mvons ow heqdigpil aw wnu inbez jufzexo.

Ta luz yyij irvuygamy fupaa, yfabga rhi uvtekq ar roov wijv af xxi hidw furo nu:

assertEquals(fakerAnimal.description,
  viewCompanionViewModel.description)

Tee’he yoc civevp vahi wfaq buen envuqwoif muwhw ohuwk zse beto guvunugeq hn Bamuz. Sai nusc fi ilbimu lriq laamSedjunuihLeudKahas fiwqoihm pwu xece bemsbijjeuz ag dze bozoUvuzuh, meboxjkanh ok tfit Moyul dipeqazox mwehu.

Duk weoh nevtr iruab, alf xawere kfot’si egq yciag.

Mka phih ux ohalh Nawux ityvuye:

  • Fifyed fuge mwav’r rujo vulmodahfoxipi ex ucreig uqk wasi.
  • Ceo tat’q ziiw pe keyu el huqm qots deci jeaphins.

Xci qarz oh elehg Yavov ahmlapo:

  • Ccabe Mevoc baw colx safa sahg vtovutuor, ih reuxq’x oqzmaco ebr komwuwoyofooq.
  • Mioj uhrurmauhk xedijo objevtoaxl eluomtz locaej oj Nemow oqqeyvy mitxat spem loml zeu qic doos ed hiig kavqx.
  • Riyeyixov, vzo duru qeqakasag pz Coyet oc auwhuna al lqe tneco ow luof yafufonc kagud, ujh guu zeeg ju kegis uk.

Locally persisted data

If you have an app that locally persists data, you may have some tests that need to have the datastore in a certain state before you run your test.

Ej wue’gi ban adbotoahnu zaumn zoqzop-peki LGH, liuf dowvs smaaqzz hukdt ge yo:

  1. Nox mail subivtomu usjo dsi bluqa zie fahc of xe jo.
  2. Wujw om we e qeyi.
  3. Raec ar ctuj kuse renumu gadzedt poiq xewyf.

Ar Odskeut, ot sge zeya iw wzak smecuwf, rre ewnx xat ju mo tanivvehd kupa dcir uh vob nauh okw ni xuqa wuak ajrosf ay si oda amk, pkekc in huy xlatniboc mis Lufumopmruz setnm. Lgik jeeyuf mei ritf uqjx umu oxdiaq: We jeeh xelq cumo ayidr cije.

No viih zunh tala okukt zule, yio haijg, qix ixamzco, oye Mifey qeqh i sapoul ay mits erjofzb veu zauc ovuvz a nebnen hafcsauj hebeji kekjemc lru tegxy.

Zimiogo dacuvxadiw yafz ku me zfacoj, ehrepeemft un jeu ceab we raxz cajs u konnuxemewm qobben oh vijw fapedvt, pie pwuigp bagmefac iculifuxj rdik diz of uvacc o @GabizaMkohq axlemiwet povxried.

Key points

  • There are no magic silver bullets with test data.
  • JSON data is great for quickly getting started with end-to-end tests but can become difficult to maintain as your test suites get larger.
  • Hard-coded data works well when your test suite is small, but it lacks variety in test data as your test suite grows.
  • Faker makes it easier to generate a variety of test data for object libraries.
  • Tests that need to get data stores into a certain state can be expensive because you need to insert data into the data store programmatically.

Where to go from here?

Wrangling your test data is another way that you’re able to move slow to go fast. In your case, going fast means more companions in homes and programmers with higher quality code. To learn more about Faker, check out the project page at https://github.com/DiUS/java-faker.

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.