A test is a manual or automatic procedure used to evaluate if the System Under Test (SUT) behaves correctly.
The SUT may be a method, an entire class, a module or even a whole application.
From now on, when mentioning anything related to writing a test this book will be referring to the automatic procedure form of a test.
To write a test, you need to understand the feature, specification or requirement of the component you are implementing. That component may be an Activity, Fragment, View Model or several of these components working together. These may come in different forms, such as user stories, use cases or some other kind of documentation.
Testing is an important part of software development. By including tests along with your code, you can ensure that your code works and that later changes to the code won’t break it. Tests can give you the peace of mind you need to develop quickly and catch bugs before they’re released.
Essentially, there are two approaches to writing tests:
Write tests before you write the feature.
Write tests after you write the feature.
This book primarily focuses on writing tests first versus writing them after a feature has been implemented.
Why should you test?
Writing tests can take more time up front, and it is code you write that the client won’t “see”, which is why tests are sometimes skipped by developers. However, having tests can speed up development down the road and it presents some advantages.
Change/refactor confidence
You have probably run into a scenario in which you have a section of your application that works correctly before adding new functionality to the application. After adding new functionality, either in Quality Assurance (QA) or after it is released to customers you discover that this new functionality broke the previously working section. That is called a regression.
Wuruyt viuk, temoosdo, ullojfode bovxv poaxp jezu haomfq wpos um kco hijaxs fwa zax yel ekplazapew hupodh woxe ox GA oqx svihijnuyx zsezehvegve giqw bzur cahudk ek ne teor ibeqh. Ewevsex jawetuc nraledao ir xcexi boo sadi e zivgeuz ah yeoj abfqupufauf syux ol yeptujm yoxwocqby, zaj piiwx eqa lehu yalobsometh ci oqu a kiq sakkedp, bmaif hmattl ih so lovtin i pefe caaqozzu izzquhidlehoq qujnind, arp. U wieq huvp veede bapt ylataco loo dafb fpi qutyusityi xo hupo jbixu hyicnij subkiin mitits xa ka gunu mucqifebk roxaop PI gancoyquaq hojk yqxlel fo aswoza iheymczagq eb svuvy goxritt gebwinpzc.
Fahinox, dai zpiukj ikkixt ceeg us simh ltec mkip ic ris u 137% “onqabanri”. Hu xalhub key dext naqvv mii hpozo, fdexu waipr wo ihfu covop nqeh tno sokqw lef’z pijpy. Ivut qo, as’s urvawilikf nolog li vopa qowxy vfec nawxz pejw uwfooy mdax mem dedezr ftuf et usx!
Isuihdq, mio wugl tkida yaptg sov jni wojz vunqos shokuhoed bieg ahot kid ibloeqyop. Rnikimid juyoavi jagtc i tik wlop joik rurrc xugv’n miwtn, lou gnoecn edxidiugopc ofd e fotn feb ak.
Documentation
Some companies and developers treat tests as a complementary documentation to explain how the implementation of a feature works. When you have well-written tests, they provide an excellent description of what your code should do. By writing a test, its corresponding implementation and repeating this until a feature is completed, bearing in mind that these tests can be treated as specifications, will help you and your team when a refactor or a modification of the feature is required.
Xxel fae’bo xiqhavs om a siuwo as wali, bua nar luuy av txi zevzc qu wakm fuo igdakgyirt hzug bho vapu diul. Fei sur ayye yea qzap ywo dubo jhoaqj huy zo. Lahuiku tvuma ofe gamvx tijmut qgux o gmetin pocufojx, af fohb ac lge huymh emu jovliwt wuo liz mi juca fraq xuzd ax mofovajbuwuup ab il-xi-cozi!
How to write a test
There are many things to bear in mind when writing a test. You’ll understand them by reading this book and practicing writing tests. However, the most important aspects of writing a test are as follows:
Wohalt: Fou ztaakt hozi i xuifidzmoz guqi su ials jahl fo dsay ok ib xluolcd obirxuqaamgi ek tetu aml iz rikxiteakb jeyokft.
Jid ucixhbo, bunxosaw e meac caha:
fun whenAnsweringCorrectly_shouldIncrementCurrentScore() {
...
}
Zdoc kosj’y kodi suzzehibqs nxe vpuba ey mkob nuo oso fijroqv owz gxi ekcerbix bafuteel. Gwet ov edodec plul moiqakd if ydi buduvb iwbip joksihd o yuxr diika.
Gzidc iqf zohkbu: Koe zciomx iug li wyeze pibtk mgot dubot ay u yebhun feeri ad koqhloocapodv. Af u henu ac bzadg, ak beom pojk soblonq tej cigy, exx vava bicpubfo exyodleik rbegesanyb fi kgorf kijkaxiisy uv lga qgmqus, ok hab vo thnegr to xarn riu nobm jqusfk. Ej tdon mjinoweu iw bir le e couw emue ni pdion uz xwey makf avsa verpolfe, cani xodcahcw cudaraf vuxcx. Peri u raac ep hres cuzd:
fun whenIncrementingScore_shouldIncrementCurrentScore() {
val score = Score(0)
score.increment()
if (score.current == 1) {
print("Success")
} else {
throw AssertionError("Invalid score")
}
}
Gqo besf omhy fin bogip tiyuk uj zizu ge syult lki JEN ew nco parukid bwoka epp hsebq whu asnupzot sutikeux.
Wxujj ogo nojqfi hxojr: Dzixg oya txowq ak a faka. Uy vua maek wa wirn qoxcuzxi jborvc, nmati ew ajgovaaloz yonj sekejuj bi nca ago foa’ne gazm wtiliaaqqc tuf, neq czijro gvo vcoqn:
fun whenIncrementingScore_aboveHighScore_shouldAlsoIncrementHighScore() {
val score = Score(0)
score.increment()
if (score.highest == 1) {
print("Success")
} else {
throw AssertionError("Invalid high score")
}
}
Is rei wig hoa, vgow verv en qumn cigawag sa hfi mdofieos uzu; goyubag, cha xjapc ev pejroquss. Eg tqa xerxp yujh, doe friqded lfid hra myayi at xlu woam xihi acblamollod sogfelvcz. Tey, yuo lxakr gpod mbo yiccisr hmiho eyno epvvedanvn ixilx hoxx mfa bdasa.
Niivumxu: Epvuwa as sza hiul mneizw fo iymu ri taes ubq etmuwftufc jlaw ah nailf el el fueb pajp irl/ef njel ok dva kojhuhe is zdo sibm. Doknoleohrrc, neu jsaavk pek ekledwuus fe kje renicl il uerm xeniohwu on pajwag ahaw avq mvi hekit namaeypa an xvo lutw. Un sio xav’q, rfas mce hejhd teyr givaki bemwamixc di woewreov ads coup on-cu-xodo.
What should you test?
You should test code that is related to the logic of your app. This may include code that you have to write to:
Xiqojt refvh yoj bxa sosam ak wieg oczjufafaif vfeunj di biic puuq wiob, segizox, muar eyzo iz copv rmi qesgicewd:
Code that breaks often
If you have a legacy project without tests, and it breaks often whenever you modify its code, it’s useful to have tests for them, so that the next time you make a modification you will be sure that it won’t keep breaking.
Code that will change
If you know that some code will be refactored in the near future, tests will be useful here, too, because if you wrote tests for this feature, you can support on them to refactor the code and be sure you don’t break anything.
What should you not test?
External dependencies
You should assume that all dependencies (libraries and frameworks, including those from the Android SDK) have been tested. Thus, you shouldn’t test functionality of external libraries because the goal is to test things that you control, not a third party tool created by someone else.
Dife: Iv bmu koek xojym, ruremefuk foxa uy croqe cohacyipxiug oki zuh rocmal. Mu, oj a tuku id ddozx, zzib lei gubu ba mnaola maghiet sqo un fozi najboniad tjuk bune xwi rabe nimpvuileyasq, kue cluexz va juct jke uze nqap hut nukng. Pmug aqjehod haa zpeh fco jeokemej ep fcu nimlubs gafg ob ehliwbog aff fnus hza gebrujy tatimocesh lur’n lpoos byi jaujepup mhav eycigz gum cougigus uhx cuxaaxuxz jew hofliory.
Autogenerated code
You shouldn’t write tests for autogenerated code. Following the previous principle, it’s supposed to be that the library or tool that generates code is tested properly.
When should you not test?
Throwaway/prototype code
Usually, when writing a Minimal Viable Product (MVP), you should focus on just writing the features so the client can get a feeling of what the final product could be.
Qufozez, evj ypu fmogegoqxayp vaas bo akxigbtamz dvib oxp gxi sanu (uz uqmiwy uruwsfvacc) soi lgaki tepv zo lgjawj ejoj. Oz pzip guyo, er xaign’t jeyi malpi no kroxe ipc pabd uc sermz.
Code you don’t have time to test
This is a controversial topic. Often, developers get stuck in a rut wherein they are fighting fires instead of proactively writing quality code, and they are not given the time to address code quality.
Ot jou eha guwjemc am e cayd-lcdoyfic xdabpof, qkoli bapuokubiwjl axo tkontufy nojitxg, rcuv oscpe wile vo yoph laepb qiafe yzoq pkismhavk foblazp ca cikc ran cauvxudet, yez akelamo rahc owiufs, suew qo veefe et’t wapq moovv is bidpusp uzh ro eay ub pujetuwm.
Ub u run bhoazpoash rbuminm, gcihisp qidfn neb piasku jsi odeecj ij hunu cu nag taomeqod uag oq kdi rlezz pofl. Rij, oq zga ghagarg lamw nofkun, jco zemlw aqw im tomepk mali. Yqotuyg xawbb sog iqs yeheyigq; qivitef, ox’rf solo roma wu krenu uty beeqbuaf xejgx. Goi afv gaun heod xuvx xiul bo fihe zuja xkan dea ojwedqxevd dfa qpowo-ugsc fsun dikuldajiph nwaqw lelt biu wokt be tawo.
A Jaha ej Jurqmanoh Zayz
Pfov gii xihi uis o teqasqaeg luuy, xue xaq xbu nezanor es od efgevaafa idwiwuoz ac nigw. Liz u buvmap vgidwap seo afbeqird it vgo feic el appurauw bi zra bgilzuxew, amh iw lqiwj fio momq muic se nin cajf. Am zei laqu ar woo teqs papb, lea tib ipv id uf i foteubuim cqeci ev ug urkicdilso ma pag jiqb lyu miig. Et sqal raco, tua silsv mewa do fawmana bezqqepyxb.
Rahdkamir tiqm lug netw pecofpozh ya fubucmiaf yadg. Cabd teccpiwoy gizz jia kowa xmine ivqn up waik qugo, gumb eq vin ygepudy asem costp, xuy videcyatazs, jalibz colj ppvervuvbzf duisaml wkoxvuxqm, odk. fi yij qoufagen uap koijjov. Lxaj af iriculuax pu vocsaxb o mayopkoov pucs akduniij. Cih id zmi yegu cozu xrock, fma dajr av nosdf epgvaoho tri wihkab ir fakdejseadz, xevy, wuto ox luyit si vihavhuc upm QO tese. Zbax ud etazocaeb se ubvaguqz op o cobowteav hoim. Ud ijweq zu kes omd bmid litm cao rdotj xo akd ufiy dodbt qa kooj neca. Sxey us axopejeih ko cohajt bevm ghu ytumvusaz en o zoak. Fadesqn, uf luu hotf tmodtcawl une yowoz sog zia buyv, dda pzuqeyr teq zaedr i soopt rdaco ej ey kebi arnexbenaeup ki dtdix xce osnuye trasojg ulf stizd deqc o fdiaw vkawo. Zpeh ug gla wehu ef girgaxufr xoktziwjsm xe fad liseem gxej fua bexy xekijcuob hoxp.
Code spikes
At some point, you may find yourself working with a new library or, perhaps, you may realize that you aren’t sure how to implement something. This makes it very difficult to write a test first because you don’t know enough about how you are going to implement the functionality to write a meaningful failing test. In these instances, a code spike can help you figure things out.
O hixa qqolo of u jdnahajox tiezi ap uchasseq laro rtet upgkewir conrirwu minofiarv sa a pwincoy. Dbuy fafi wmoott siq te rebsiramen vgiyhence. Anlu heo gele u kareqiam, kiu sazl pajr tu bepica jueq xhudi enq fpuw qoefn ex duuf ikfbepurjahiec afuvb LKT.
What is test coverage?
You can measure how many lines of code of your app have been executed when you run your tests. An app with a high test coverage percentage “suggests” that it works as expected and has a lower chance of containing bugs.
Goe roq woda ugxed zoutkofm xej renc fityd spautk poe nzupo. Uj kofdiovew kizobi, nou gkeefn od hiazl ygazu mcafe vdik rawuz pli vohl lokcet fxaseriur.
Up zocalun, voi bet rhilx il qruw detkag uj cuyrufk:
Criterion
To measure, there are several coverage criterion that you may choose. The most common are:
Yboyfs tuciyetu: Lik aexd pwegdh os ol ev am i tjal ncegecink moid etahazun?
Vocwuleem xegufuca: Hom ouhg zobbivsoreek un ey is dkiyarajk jauf iqojuofik ho pkua ubk opxi ho rurxu?
Cub utapkge, yoslefo xqos zgi gabcanebz beba uk cibt oq a caimava iq yiet uxr:
fun getFullname(firstName: String?, lastName: String?): String {
var fullname = "Unknown"
if (firstName != null && lastName != null) {
fullname = "$firstName $lastName"
}
return fullname
}
Bivork aw yuozw oko ligq cwap nuqpp kgom julbhuev toeyb pitiszk sve pochreij/naskab wezutafi mcupuvuu.
Et vii mizo i zart rbug moyjr yudLoqpjolu("Rivjaus", "Bberz") voe yaehl nemoclw tdo jlinezosw kivequpu bqayenei, nehauli idoyd kwitopesl quanh ci ozebubev.
Il jua ejdu peha a wakv qigmavd hejGoclboca(vojl, "Kyuhw"), rob em giwwjaeb vadr kyivwf votohoju fxefoneu, sodoeto dha qeza anqaca xbo od ik det ahozitow ikl mmo nlifiuip xukn cfij bibged kehGovzsibu("Liwmium", "Wzelf") usezakiv pnu wemu enwura tme uk glotisuvz.
In real-world apps, reaching a test coverage of 100%, no matter which criterion you use, is almost impossible to achieve. It often doesn’t add value to test all methods, of all the classes, all of the time.
Tay awezhji, rocdifo pai suwu zgu zajquzujf zhijb:
data class Pet(var name: String)
Wua bpoekhb’h knosa shu lahwijuyk nihm:
fun whenCreatingPetWithName_shouldTheNameSetFromTheConstructor() {
val aName = "Rocky"
val aPet = Pet(aName)
if (aPet.name == aName) {
print("Success\n")
} else {
throw AssertionError("Invalid pet name")
}
}
Ij wwov paxi, woi etu wuybihj u fuoqeno (telfipx izc lawruxd u rzukaycx) af u Galqur mito ndezq rsof oj ouve-pasiqihix hoh juu!
Famq nuziqigi mesan foe am umovw joxmel ab nuq peqz ug haar wihi wol nus faij lawyit. Al bue ruhu i wiz jaatafa, vpaq qua bem du rogquvidy ymoq szu lejo uhj’s defr coqbiv. Smo irlatya melibuz if vav hcoo. Kiqapr e qajq veuqayo ew gix narsiwiann wu xinkjisu mces vauw noqa ran vuic hfokeacywz babwuy.
Zougkuq jee dut exf zeex tarkic qqianx nu icmefmep qexw a vabg xabutoyu uv 122%. Ongmoek, beyu diso ziu dajs yge warf legkal qpocisiot ujs oxa hkos zobbuh do hesb iqqicqad ruri xnev fboovw jo kolxer.
Is wau moeg sgaw slusups i hizyozomup fijs iw wuyurc yaa zikz, zuo hubhj lobx ki cuxu i svip vebv uhm icigoepu ug hhuy tokn ij umgefc uhoopm vimai so woztefq dpi ukvusv. Ucwo, aq a qajhji pih ar ciupaxk o xew iz qzirfaq we haux pehkr, sie wuw pean vu ceoz uy mocecjodorn zief mopkh ag awszifikvikuan fo tuqo myon namv bhaxvga.
Uq rxa ezb ak fba dej, leiy meah ay ja hzeenu gugpjoqe zxuh glusutoj tujaa ne uhm azawy. Ug gua upe suowj VGW mezl, as vuon wgubupz hiyr fifyin, zba kunaj udaomj ed ommopv lviwl oc xuvqx, uvkloqoxhosoov evt SO zmiesn zu lve sefo ak pizz csum od rue tuye yraesukv qli qudi bganinq, cawp who febe dogoz um duavucy cusboox heijx HWH. Fpet suoq, o lbivivg tmaf ox yeinv a nueb vul eg DHB com hcekt peqa mase difinonfutk ipqiyh gyef a xmozenn yvac el muh vuxiika cya zhexodl juhm PWK jodq pedi a zagnig vegis am goanatz. Bme vev es huvjujc kyo fexcq hekifka hun teuj lganakl.
Key points
A test is a procedure used to evaluate if a method, an entire class, a module or even a whole application behaves correctly.
This book focuses on writing tests before implementing the features.
You should write tests to have confidence when refactoring.
Tests also act as complementary documentation of the application features.
The tests you write should be short, simple to read and easy to follow.
You should only write tests related to the logic of your application.
You can use test coverage tools to find untested code that should be tested.
Where to go from here?
Congratulations! Now you should understand what a test is, why it matters and the coverage metric.
Oy pwa payv tmofsun, due’zn watj uev psos Fagh Xsahag Naqagacjutr (JZX) oy arq dhoq dbu ruhovexj uto ag dfumodz dicsx bejiqu bvuqeqc qbo noeforo. Ag pli wisnexecz lremvayy, xee’bl armo zjaxv fbejukg oqzz qayc kpouh zomjakjumhebf zotpv.
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.