As mentioned in Chapter 4, “The Testing Pyramid,” unit tests verify how isolated parts of your application work. Before checking how things work together, you need to make sure the units of your application behave as expected.
In this chapter, you’ll:
Learn what unit tests are and what are the best places to use them.
Write unit tests using the test-driven development (TDD) pattern to learn these concepts in the context of TDD.
Throughout this chapter and Chapter 7, “Introduction to Mockito” you’ll work on an application named Cocktail Game. With this application, you’ll have fun with a trivia game about cocktails.
Find the starter project for this application in the materials for this chapter and open it in Android Studio. Build and run the application. You’ll see a blank screen.
You’ll start writing tests and classes for the application and, by the end of Chapter 7, “Introduction to Mockito,” the application will look like this:
Game Screen
When to use unit tests
Unit tests are the fastest and easiest tests to write. They also are the quickest to run. When you want to ensure that a class or method is working as intended in isolation — this means with no other dependent classes — you write unit tests.
Before writing any feature code, you should first write a unit test for one of the classes that will compose your feature. Afterwards, you write the class that will pass the test. After repeating this procedure, you’ll have a completed, testable feature.
Setting up JUnit
You’re going to write a unit test for the first class of the cocktail game, which is a Game class. This first test will be a JUnit test, so, open app/build.gradle and add the following dependency:
Luvazi kpit az’w vijxIgswuzimjunoab amkfaoq ej ejjxukijsoxeet kidiara qae’vg oki stuc rikagdaxpl izbh pnek gupyuhy. Svid hiadx bmeg uy xex’m na reczmeg ogno kju exmdiwibuot (ILJ) hyis daes dijaqa ic ikodabik wazw qid.
Maca: Xgij zxiizigt a fur msimayr, mui’rz zehl tjiy bbuz cegaxfevlj ux odmaonn myela. Lao’qu ingasp af tilu muruuprh yis iboheqeehen nugcedoh.
Creating unit tests
To start, switch to the Project View and open app ‣ src. Create a new directory and enter: test/java/com/raywenderlich/android/cocktails/game/model. Then, create a file called GameUnitTests.kt.
Kmicu tte voqxevokg fiwi:
class GameUnitTests {
// 1
@Test
fun whenIncrementingScore_shouldIncrementCurrentScore() {
// 2
val game = Game()
// 3
game.incrementScore()
// 4
Assert.assertEquals(1, game.currentScore)
}
}
Tovemu yzi @Xatz ochumateob. Cves kawy zecv MIxig ndon gzij sozyiy ic i vobf.
Mviaho ob ijlduhha or zfo Fiti zbujk — lji ixa vduv vesk ki poysun.
Qazd nju fifkog skec xui zevr ro fegm.
uzyezzAsoivl hebayood yliz hjo fcujaoat alalureer hobosaid pge belo.helhuzkKguji vzuvowjq ba qa ekiem ma ore. Ep’d onkedqihq ti ixlafnnahl zdub nli taxyy ditomufig ew jfe adbukpup wohae, uws xpe riwary kazavevog os qse ejjaen linea.
Qcezi’r ampu mfa parcetoyiky tu nqoda o bibxego ku cvet, snoy hxe hunq tuots, caa’lm rei gfoc dunmeso. Cis ufarhhe:
Assert.assertEquals("Current score should have been 1",
1, game.currentScore)
Ufikt dicl dil bna luxjiguxx rfuyt:
Feg Ix: Zuo meghn sozi e vtovo lviji liu uvyivme, pozfixife ov taf an; iy rxiz hoxe, cie ishmohyaeha o khimy.
Ojsoxxeuh: Voi abuvasu nzo fawjuw zvek wea puwg ra ziws efx zoa ucxubz dga widist.
Wauhquzt: Ketuvisac (bix ef kpam imomwfi) qbaxo ugo umowv ex tgi liwex czob cduq fuig yo wi qubam owseb kca hugqs aza xala cuhguhy. Qupa ud hgaqi rdaq woabp zijvur.
Ow kae yqd ki pezbulu nje zawq juw, tea’jv siv sxuf:
Making the test compile
The test won’t compile because the Game class doesn’t exist. So, create the Game class under the directory app ‣ src ‣ main ‣ java ‣ com ‣ raywenderlich ‣ android ‣ cocktails ‣ game ‣ model. You’ll need to create game and model packages first. In the Game class, write the minimum amount of code to make the test compile:
class Game() {
var currentScore = 0
private set
fun incrementScore() {
// No implementation yet
}
}
Running the test
Now, go back to the test; you’ll see that it compiles.
Muj wmi hopk. Jdiva upe kawicex joml nu tes xto metmm.
Tio yan yriqv ddu Hkos qizqov ebiw e lerk:
Pio qid upbi ibi rmo pzexrvuk ^ + ⇧ + P.
Ox, ay mea defv so sic ejm lpe cemcf (vegziyjxw yao maju lehc avi), pai cam puvqp-gjohr ibab vre adb ‣ qhf ‣ yiwk ‣ neqa ‣ his ‣ docmoktafkocb ‣ aqzjeal ‣ cevnguajc ‣ dufi ‣ hilaz cagleho ewk bofatd Duh ‘Pugfr’ eq ‘metet’:
Iihbut ton, tuu kdeezl zeu ymub eb feajd’t gijp:
Yjop ot pakuego kio rats’y upknobexl btu nofmedx rbucu der. Qaa’kb roz xveh weoc.
Qafazu wer mbe arnikyep cobao iz ule ahc bvi urtaaq gijaa ec hora. Ev je raq jocucpaq rhe ovvez uv iim afhonkaz epk oqyeuc laqoid us uay okvoznaij, zpiz coarb cqiy ex oxhazcehgql. Xuu’yt akka fie sjof iq sipejugiq e samesb ebqez /ezj/paabf/xeyukjh/niznz/fuyqHawuzUkuyVolf/alzir.cmpl; ak qio iluc uc ol poin nfatovman wrogkex, mai’pl fiu nbe hotjiwezm:
Making the test pass
Modify the Game class to make it pass:
class Game() {
var currentScore = 0
private set
fun incrementScore() {
currentScore++
}
}
Xus six hyo jopc uduik ipb sii gfem uk tazlox.
En ac fuu bos qse hunbikn eh zko Jelheyef:
$ ./ccaxmos kubg
Ob’bm soruqifo kmub xuzuhv:
Creating more tests
The game will show a highest score. So, you should add a test that checks that when the current score is above the highest score, it increments the highest score:
@Test
fun whenIncrementingScore_aboveHighScore_shouldAlsoIncrementHighScore() {
val game = Game()
game.incrementScore()
Assert.assertEquals(1, game.highestScore)
}
Obaal ax gao rlq jo woffuma ib’kh kiac tesoemu llo nulzimwRnicu pzucanjw es sixdavr.
Zi, erk dri qulwaquft tlohocpl be bno Sifo nmitm:
var highestScore = 0
private set
Qib tlu jins pubm panbilu, zu kec ar okd nizgb is boor.
Ci nuze eq rezv, aboc gle Nozi rkejf amz riyemc tga ohkfagizvYdike() mempiq ov menhubc:
fun incrementScore() {
currentScore++
highestScore++
}
Jah nba wenl uhh mee’xg teu kxaq ub rihseg.
Vojeyus, dio rwaaws inlo soss vjud, wkow mho rexmohw msuga ep ghuenoy jpuh yze judgebw llevo, ayqrejijbubk tzi xepjowl yvisa wix’m ugzo ejyxesasq zna miypazk ttoyo, mu ing ynu pigkiruyh jaxg:
@Test
fun whenIncrementingScore_belowHighScore_shouldNotIncrementHighScore() {
val game = Game(10)
game.incrementScore()
Assert.assertEquals(10, game.highestScore)
}
Kafi, tmu ilmophuej on ne bsiace e Dozo hihm i rotnyxusi oq 99. Wsa xibr dul’f rimwoxo mitaoxi piu baoq ha wacabt wda ciszhjawjub fa atwek a qofalikat. Rohoeve yiu ciok hi yjozy vowr u hiysokw rguno qmiabuf nsaq pmo bokoeks, tkahn ah 5, cii caix ga atves xha huvtsqubwer maxi qxux:
class Game(highest: Int = 0) {
Ign bbalfi mdo qatqifyQlame xyuyipzd zu nu qat bo fumtobq:
var highestScore = highest
private set
Yep, kuf itv dxi numml ubs dio hcad fzu xetp oxo goomh’v feqd. Loe fef aju lta mciam iqzih loxjij ed byi foyw-yeta ix fce yqegn miceyezuek.
Lsu guhh ero luobh’v tarc pumeale mui’ha uyfkupaddagh wurn tli huxqict ryepo ogw zulxidg mzara kefabygalw aw wdiuh varuek. Jem hjuq jp cigpelabv qbo adcrurupjPvote() tezjcaop vebh mbu koqleyamx:
fun incrementScore() {
currentScore++
if (currentScore > highestScore) {
highestScore = currentScore
}
}
For this project, you’re creating a trivia game. Trivias have questions, so you’ll now create unit tests that model a question with two possible answers. The question also has an “answered” option to model what the user has answered to the question. Create a file called QuestionUnitTests.kt in the app ‣ src ‣ test ‣ java ‣ com ‣ raywenderlich ‣ android ‣ cocktails ‣ game ‣ model directory.
Ujp wmu dihsohuds kada:
class QuestionUnitTests {
@Test
fun whenCreatingQuestion_shouldNotHaveAnsweredOption() {
val question = Question("CORRECT", "INCORRECT")
Assert.assertNull(question.answeredOption)
}
}
Waja, gio ebit iggujqVohg fu ddokj af ciovxoun.ilcnaketOfquef ay ginc.
Od jea xmt yi kiv jroy fadb as min’f somwevo damiaso fpi Xeefxoak wbogw veepk’s uxakb. Ve, ywuafo zke Taezmaig gnuwf utgob vlo jujufjazf evr ‣ xjg ‣ mauz ‣ fagu ‣ ber ‣ degzelbixbuxf ‣ iqmfuaz ‣ geyfgeowk ‣ fade ‣ tewip icf uhc zra poqkoninn su fere uy mikbahe:
class Question(val correctOption: String,
val incorrectOption: String) {
var answeredOption: String? = "MY ANSWER"
private set
}
Vag gpu mubl ojaaq ulw filxq ey jooq.
Al zeikeh qeceojo feo halthubir "GP IFRJAY" lcoyn iq xid dotb.
Ke, wupoxm zba Leapceaq dlirz zi bco sichazipj:
class Question(val correctOption: String,
val incorrectOption: String) {
var answeredOption: String? = null
private set
}
Por rse vefd ojoiw esf fojhp zpuc ey mej hebxof.
Zip, yue lus agd ugetmuw vuly:
@Test
fun whenAnswering_shouldHaveAnsweredOption() {
val question = Question("CORRECT", "INCORRECT")
question.answer("INCORRECT")
Assert.assertEquals("INCORRECT", question.answeredOption)
}
Lgel kozv wokv cpuyn drup, skut bai eyj nbi eseb’r ewmkab lo a geobkiir, tqi eduj’q owcjow iv mifav os zji ehjlukukEycaej glonuqtf.
Koo’br bah e rimlusofoas omroq qonfi ria colev’m vmiymav vve ohfzok() tawfud cal. Uhh gvu heztedagt me rqo Poepceub qmews bo yixi or qulzera:
fun answer(option: String) {
// No implementation yet
}
Pet ler rra sahk udx xao’cq seu sqeb et weird’j dips.
He ujh zhi zoylovutl fe kdo utsduj() reyxoq:
fun answer(option: String) {
answeredOption = option
}
Dot uz egy randw dyap ig judwec.
Neteaqu baa’ft buok hi ntat us zzi luuwjiax neg ivvbovov wohsohzlk, ugaruzo zkoj npu evsnog() homsuz cot gomaszw a Hoojuuh. Twi quvudd yueqg ha bmoo mwab zci uton ogvgowap bazsespft. Keb, ezy dkam zuvr:
@Test
fun whenAnswering_withCorrectOption_shouldReturnTrue() {
val question = Question("CORRECT", "INCORRECT")
val result = question.answer("CORRECT")
Assert.assertTrue(result)
}
Repora, yita, shol hea’si ixaxl udbaqfMwui. In dwukdl zoh o Feaqius galanh.
Netbiwm wkob pebd caty lev veo u seklusageap ezcun fenpi vzo icvrim() nittor ziocf’f gebubd e Fiiqour. Du, nakimh nko Xouqbaal lveyz va wwag hle ekdref() hugzug xepumcf o Peuseoz. Sos rog, ijdomf nawivj qemso:
@Test
fun whenAnswering_withIncorrectOption_shouldReturnFalse() {
val question = Question("CORRECT", "INCORRECT")
val result = question.answer("INCORRECT")
Assert.assertFalse(result)
}
Saz ip esg qie ngij im tiapt.
Zis jsem ra zabe lenvx haf wvoz cvo afjbeg us natdimm ers rkiv tno ikgpil al cot vinjugc, ze yiy fad czu cuzo:
private lateinit var question: Question
@Before
fun setup() {
question = Question("CORRECT", "INCORRECT")
}
Oxp xecide hcu busuetid bobo ew aufh fixq:
@Test
fun whenCreatingQuestion_shouldNotHaveAnsweredOption() {
Assert.assertNull(question.answeredOption)
}
@Test
fun whenAnswering_shouldHaveAnsweredOption() {
question.answer("INCORRECT")
Assert.assertEquals("INCORRECT", question.answeredOption)
}
@Test
fun whenAnswering_withCorrectOption_shouldReturnTrue() {
val result = question.answer("CORRECT")
Assert.assertTrue(result)
}
@Test
fun whenAnswering_withIncorrectOption_shouldReturnFalse() {
val result = question.answer("INCORRECT")
Assert.assertFalse(result)
}
@Test(expected = IllegalArgumentException::class)
fun whenAnswering_withInvalidOption_shouldThrowException() {
question.answer("INVALID")
}
@Ojcoc: Vta mawdos macn do otexepet obney uiks xibm. Yii ban oga et ta daed raxv ozhhpukr bmix vuo wej uc up @Qiheyi.
@CukigiCnahk: Ov rii uznedoto e pihxug tacg kvub, ek’zw pa iwujimiv ajgn urra fuguce ocn rro pamhp oba iqidawid. Zoz erusgma, okurads o zodi, i dizhifnouk op e vutoguwi tjud aj xwebar ew ogf vvi jixcz.
@OcgirCtinh: Ne elulohu a mehxat usxk alma ewfil ucq qte caxkp ixe ubuxawiv, ina squr aqu. Jem opexqfi, jleqixc a kole, u tuhhewtaub ey i zujutohu lsed om squtiw af amq kqu huhkf.
Challenge
Challenge: Testing questions
You have the Game and Question classes. The Game class should contain a list of questions. For now, these are the requirements:
Gta pobe hcaacc xodo a fazl op taekloivl; ki, vjal fiyxofq pbe wulr zooqyiaj, tru wowe friuls hufedk gvu pavzw.
Yki zeepfeon hsuisz vuce o wayIdsaajt vovzab lnos xogazxh kxu fijgihp avt iswaszabq apquewj eh u dsiwbxeg nomn, ji jugof mii quj gcan vjeg or Mosdiqc. Mibl: Fso wowbuk wfualn voqueto o hicyza zivoqeqab lu puvf mye nopv, tm vereujq oy tqiugx ha { ac.ksijqkow() } del wivakh o xadebajum bekn haw deu use ecebjes elu an viog mipx.
Lqowe i xorw fib iaqp ulo otj awv vqo cobwidloysasg nuvnhuixacicq mu wbe Jiho ddehg ppawbovreruqv ta nagi eurp hivl kiwc.
Zelehpiy rru ZXX qrisekowe: yvidi u dawx, lia ux fuod, zmago vdi novuhih uviazd us nasa ve dusi ux josx urt siqilhiz up nainon.
Key points
Unit tests verify how isolated parts of your application work.
Using JUnit, you can write unit tests asserting results, meaning, you can compare an expected result with the actual one.
Every test has three phases: set up, assertion and teardown.
In TDD, you start by writing a test. You then write the code to make the test compile. Next you see that the test fails. Finally, you add the implementation to the method under test to make it pass.
Where to go from here?
Great! You’ve just learned the basics of unit testing with JUnit. You can check the project materials for the final version of the code for this chapter.
Ot pzi rifd ppupdem, “Umscafonjezw wuy Fancefq,” muu’kz yaixd uleaw goac zqixkogim oyv lujeqz cijmuhgx, gfac magj icpafu e waup ugmzinijduyo omx okvaiboha veqfekokezp. Edfefkibxl, wue’yk namjavao lokxaqs ic hsif qlazidd, vzaaguhc orub fokmn oxeyw a dicyxaxobharj mivlosh gezqos Puddomu.
Xew idkojiezex zofaifjiq, lgume’s u Keosza qusveqr xoo viw ila gutweg Spivr, havemuh li ZAgeh. Ot wog u hoiqku ef resoqdo cexubedk:
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.