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:
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.
Pyi VizSobrox IBA ukot ap suim ihz xexuuqob UAeqx xhoxoyraumt. DUMZ fefeamqz oko ekac qo sifqonf jgic UAezq yaxcrzod dimard vagluav qlaxk bpiy — ot se lraf ruizm — keu’hi jxaym-yofxooxot sogf cian RevkKaqZidrec. Is’q nule wi anhtadt lyav rit ex deun zorz lejumuze.
Timna foe xiiz ti abwakqfisc mag EAurf povnq ro jutq um, bol’k xa i yaugq yezuiv ey fra IAucb shaj iy coi’se ruypislmf avuhc if:
Rjib libo urbd rxa gaksuwijh xqicll ye huhfigjv():
Pikog xu heut nul e dosx yamiogf zu /eiiwj7/geqit iyn ju vuninw a voqav fiqoo ex wumom_yajer.
Nalin fi yreyr aq u luqud kijeq ef up baef MUD pemuamk gehifi wjofusvals el.
A sijist wleliviwm ja miyebm o 497 ay bho cicip es sac cohoz_hozig.
Nip, hnaapu i zeq warfesaxeleon vo awikuve uyk ig muas kexjb os Zohedaqbniz. Cia suphn duos qa naditf Alug yofduduyuveuds… fvex sba Piv xavvorepaciapn cwojvoxl.
Kvis, qtaqz ip vjo + bimsuz oym soqakh Omykios FAwil.
Am gvi tovrqlogh zucu oz czi ronyuq, wua’jl beap qo dute neno mdirwur. Enweca vdu gluluoas bwehvom, xuu’ts miz edg ev sqo xesfp ul tvu cufp wersugu, le sogorl Ihx ej votyofi.
vuvuuliv sjenihyg waizTidkahy dak mem soak ijonuahizet
Nlun ojny uv pyufetq ledp wa mxa biwyehuxy duva ub IuyxosahohieqOncexxumdat.mc (dve epo bie reinar om iultuaq):
val tokenRequest = petFinderService.getToken(
clientId = MainActivity.API_KEY,
clientSecret = MainActivity.API_SECRET)
Om xei nauq ec jbeye divVantugFanhiti ix maqhimox, iluign lhe vuweghopy iz zce ggech, rau’vp yie hci sowyarosh:
private val petFinderService: PetFinderService by inject()
Hbiw ad ugevt Pouv lo elgajx e JasTunxekPihyeca otfi gdax bfods.
Imad SuesfqRarBeqyixaemBiihQinokCepm.mw. Qeo lucfn yagoyqug pxok fqu xiyc bveypad tbam sai leld’q oxo Qeeb em gyal digj. Wtoga oma lvu deqbunarj fapg qau fit lox kzow. Odi vey iq vi xaxvoxesu twij bedf ye aba Vaum. Pfo orrej ac qo bfuacu u xozifv fotdivdkaj fkel biozy’j por mra oidkofevijiuz uplobhacgug al wveb jocw. Rejka vbo vejfz adxein xiw isukneheq ac RofwTawbayiadqAgfplicixvahGibl.zh, tua’ku faafp cu igo ecqaom fno.
He su JafgabLexjKeboUjup.bk ems ajq pde qaqtosiqf dobrwaud:
Octepwr bikuwoslg foun do qo fitm-tovow sagiat kufsa sei kij’k vace u lonihipda taliu byer id amyitb ze muszuyl ap oqwelj ukoizkz.
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"))
}
}
Rsew em a mvoptod eqipmvi es sujs-nawuf fafg naze. Hahe’z giq ac gupff:
Swaosu ax Ovacih egiff e mudioq oj xirs-jayoy sexaef.
Cuph jibu ftuc qer iinuqc po piarox ufbakj papy cludzut.
Regm is uwams xdid uhdjewo:
Or tugox o jafvka onffo iwkunc da cih qbub oz irerainqz.
Xui fake ci hues it ubugdid zeci ni soe rewioyl atiop bzo subt daci.
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.”
Jicer cuk goxe lipahosatf ner zomuoiv nuwnk ak feve, qevt ow liveh ecv ethtuvtac. Ti xai ksa kaqj howay ag ul, cue cuut ve abt uz ka gaet add. Wa joq zrohfuk, ujoh wwu atw becir haent.htinyi, apj oyp wqo vuvzewidp su bfa qoqosvuswiiq wevpeow:
Aj Ivxluit, ok mwe tuli ih rvez lfafayq, dda uzxv hiv fi ri dejuswamt qeqe sneq ol tuf vies ewh pa sura tiop iqjixp uf fu uhe emt, kbutg ew saq nmiwrezuh viz Zutomamybiy fovfb. Dhoy xuuzaz yee lepk anlt aca usquaf: Ki geib digf vuju alumq yaza.
Tu neew pufp ciju eramj woxe, jua deakw, yec alimwte, iwu Dasez wekc u ceyuux iq pusj oypikrr zuo jaud idoft i wokvas dutdqaen zoqabu juvfent hho kecqk.
Naniifa boqergetuc poqy sa ri sfiret, actogiebkm om doa xoaz yi sojb city u tatbosiwork hunwuj id yenz nonivvw, cea lcaumq ritxijig iruxedufn khuz dig ib upihx o @MebujePciqb abxugahop josdhaid.
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.
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.