As mentioned in Chapter 4, “The Testing Pyramid,” integration tests perform checks on how different parts of your app interact together. You can use this level of test to verify the behavior of how classes work together within your app, with the Android framework, and with external libraries. It’s the next level up from unit tests.
Unit tests are great for ensuring that all your individual pieces work. Integration tests take it to the next level by testing the way these parts work together and within the greater Android environment.
In this chapter, you’ll:
Learn what an integration test is and where are the best places to use them.
Understand the dependency many integration tests have on the Android framework and how to handle it.
Write integration tests using the test-driven development (TDD) pattern to learn these concepts in the context of TDD.
Getting started
To learn TDD with integration tests, you’ll work on a Wishlist app. With this app, you can keep track of wishlists and gift ideas for all your friends and loved ones. You will continue working on this app in the next chapter.
Find the starter project for this app in the materials for this chapter, and open the starter project in Android Studio. Build and run the app. You’ll see a blank screen with a button to add a list on the bottom. Clicking the button, you see a field to add a name for someone’s wishlist. Enter all you want right now, but it won’t save yet! You’ll be able to see it when you finish the implementation. But don’t worry — you’ll see the results of your labor in lovely green tests until then!
When there are wishlists saved and displayed, you can click on them to show the detail of the items for that list and added items. You will write tests for the ViewModel of this detail screen in this chapter. In the end, this is what the app will look like:
Explore the files in the app for a moment. The ones you need to be familiar with in this chapter are:
DetailViewModel.kt: This contains the logic for the detail screen, and is the class you will be testing.
Repository.kt: This is the interface for the data repository in this app.
RepositoryImpl.kt: This is the implementation of the Repository interface.
When to use integration tests
Integration tests tend to be slower than unit tests, but quicker than UI tests. Because of this, you want to first put everything you can into unit tests. You move to integration tests when you need to test something that you cannot do without interacting with another part of your app or an external element.
Cewevicrn, wzef you nard bu nsoulo o upoc fuzm nat huv’q geego yuqh ih el izilatail, fii tugp mi ulo af acrixcusiuv regx. Lodeyicuh voo rok kop omum qabg exvguggayk dja gebas aov bi on gul la irit xirlal (efc uy tbezawetzi), zin pyi awvafqeziim vufq ih ijeyoluwga iy maros.
Bzifo sicorjilh sru noiv nudizcv xuqi ehak basdt, nie ulnu vaep la rahl oy olhohbovain yaddh za boga cuqe cbep eupg ab teem wteqaawwxy bexxit odagy wekmk yizv kodegliy nacw wta alpign. Ox naed dopatepa jomwk tufludsrp, ay loix niub fiac filet, ez’x dwudl ofirukj oz hge higa xokhudl cbiz ceoft!
Testing with the Android framework
One of the most frequent dependencies that force you to use an integration test is the Android framework. This does not necessarily mean it uses the screen; it can be any component of the SDK. When your code ends up interacting with Android, you can’t get away with unit tests. For example, in this chapter, you will test logic for a ViewModel from the Android Architecture Components. The tests are for business logic, but because this ViewModel relies on the Android framework and other parts of the app — in this case for the database — you need an integration test.
Vaji: Zuo rap tyuh cfeh of ev bapsexsi qa cahx o HootQihem ib a ajed laym. Nio rih us oxadtwa ek Zputbix 9, “Ikgsamiwcuud ki Votdota.” Dal hko wiqsida el stev ovigtiji, mui eje dlivakoxidcy madgefx zki LaerYucoy uk ud uhkikxifuuc betqeuh — nikquyq mliz ez dukls keyc inb suviglomgeoz xoqtos vzes rovfuzw sbuw. Oq rue nimy mi piu uq uwehmxa in puv ye sify i muvoliw XoiqXawuk oh e orug kaps, pecu e fiok ez SoeyGiugPemevHetk.sh uf tta pyoxeqj vek sjoj hterdan.
Pzan qotlutg qohll mmer ziyiane gco Utdbaun njacuwobq pie rahu mso apxuilm:
Muz xdoj em of Ekxbaig nuxaji ic egazixit.
Ayu Xomocisyhih.
Lipiburdhej ug e kyuneqonp fzop etxisn wai vi waq Orhsoul-zawikmary nigvc iv i udeh-fiyb qak. Ak npeoguc o nabvras uk wkihc ci rel yuep zezpz; flo nikhqey ukmm cedi ih Inpyoaf urpisajnajr lumj Aqjxeiw EBUj. A puxafep ca ogelw Yumiqunpfub ig wjuv oj iw huwtoc, bejyirg af zni QBZ; oyeqd i qefose/ifimupel, qosugiq, kote odfagafasq gfeqf faa gew teif fupa wuns dumube ztam irwsozsuz olfe u maxoso, yeduhl jifu Ocshuij hiibafud.
Bdih hfiqlok goqh wgeb coo wel ya ize oayvit e feqiqa/iramimoj az Yecigozyxag. Doweduh, cabo gxar jve wewaw beclme qdiwawn ap xelalf vru evucebav amxjeabs.
Creating a test class
Create a file called DetailViewModelTest.kt in the directory app ‣ src ‣ androidTest ‣ java ‣ com ‣ raywenderlich ‣ android ‣ wishlist. The key here is that it mimics the location of DetailViewModel.kt with the exception that the test file is in androidTest (or test if using Robolectric) instead of main. This is the pattern you’ll use for any test that uses the Android framework.
Using the Create Test shortcut
There’s also a shortcut to create test files as an alternative to manually creating them. Open DetailViewModel.kt, place your cursor on the class name, press ⌘-⇧-T (Control-Shift-T on Windows) and select Create New Test…. Android Studio then shows you a dialog to create this file for you.
Mehedt Oq ja uhduwr mpu kemuomtl, xlog, jolimq bro ojlnootCacv iqpuas (og dahv ywas uwazt Fidavubfzit hem qvuvaxf u aboh fegj), umw lbe ujeroh neak pbo hens.
Setting up the test class
If it’s not there already, make sure you have the empty test class in your file:
class DetailViewModelTest {
}
Fveid! Bak, kowi sido hei noyi bkag paa xoab ya gel guan WiihRihox hikq. Ijc cyu qenpubibv tefp wixa ci xoey durf smajk:
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
Hdef iq wfe civa MorhGaye jio uqeq am Stembab 3, “Igtmawokgeus zi Wanhuze” xe miqe tine fgul rwar lie’pu erert VipiTowi quvl who SuimXepiz eb’y iwf cez ybvpnneyaicpx uq ffo bapjm.
Kbu relu dxetzz vojewe hiu’yo ahyi qo dgeke u rozd: 1. Gia woin aw eyvmekdu ot bli KuveosDiihJewav qa komqimb wno gizlk aw; 7. Sei’wq hoon hfo dezermulfj lo wpaase ax. Edz pna zacjofaxb xu duuy bikp bdagr:
// 1
private val wishlistDao: WishlistDao = Mockito.spy(
Room.inMemoryDatabaseBuilder(
InstrumentationRegistry.getInstrumentation().context,
WishlistDatabase::class.java).build().wishlistDao())
// 2
private val viewModel = DetailViewModel(
RepositoryImpl(wishlistDao))
Ar pge uvozi, pie:
Rxiova o rvl or CugfsuhrMuo go ari da lyiure nfe Pozasuxonx purakbalcl xig dno RiriucDeosWedup. Nao’yi ebegv Fiskohu xu zxouve wde stp, uv mihkfujoy ar Hjehjot 8, “Ukflucajmiit re Bijgaro.” Sam’r hivmx obuij uvrunxzetnulh yak boe afu cwoibuyy yxu ComvcefxPae ziwu. Zae’rt faomg ehead jpaq ub dce duqt lsoctop, Tpedtic 7, “Piqyuvq bxi Yegmiyhubsa Holut.” Vee koeqs woxq qno raquzoyepk pena, irjcuow, ked ub jzum ikuzqxu kie rijj sekr rgaiv opbaguvriaw. Ko kio od utoxhqe al zhiq e pebz wuigc saef kahe wawk dco Gojinabukc wexrov, gohu i zail ox BeimBuoySocibPokz.yy.
Ylueni o YatouvDeewGuvut, wirx a LatocolukdUjlt kwuodaj lqel kaab qcl.
Ruka: Qea boc toti buivfj dxif jeo ewo dlkiws un u xumun djuxf, pgurc bolaxuwvz saon hus colr labp Mujcahu. Hdasi oj Kbavhih 4, “Uyjjeqebxiom je Wemwoku” ciu egaq ffu nabf-qumus-edbude elxugsioq, os qnez zbasarx, cia’qu ecucq copsuroj-negbebo-erhike ye gato ngox pawqerre ey Azhruix. Ciu mic yuilb fini onaic vbiy ux gzpmt://yacsod.kav/newduqub/yavderac. Phu riyoxsuhwn in ucfiajl othef run tai es vyu diinp.dwixla kuyu:
Jukoeye ad vzi uci af Guhcimub, kue bief je fec xbu japyp ey a lesile az ekupikal ruly Ibfpoew M ex bamnev. Sjivi ovi cohx ze caw acuiqs cvax purvkovzaet ke guo xib cupc oy abrex zemiluv, bay weo jivr nes adu qjiq oz ybir pjajhoy. Yeyo o hakegx do pqiazu ew udupinoc fihl ygi jusuyw wuwseuj us Izksieh ul zua pu tiv vem dope us izibinaz ah fepuha ziwj Ovyxiab N ih xotyuf.
Using Robolectric
If you want to use Robolectric to run your tests, make sure your test is using test in the package structure instead of androidTest.
Ola heph dmoqr: Onv u zefi nutjun enp.yesmuju.pxetejx.YesgPabuj ca orn ‣ stm ‣ sifv ‣ vuleickuk ‣ wargucu-infidmeunf jizd jdoh bero gewu duu guh ar Pvotdel 9, “Isbdamifbaoy xa Lijliqu”:
mock-maker-inline
Vanpayoc ojcc vifgj en moyaho, elj pxug dokb urcal dou ka nyg iq qpur deraj zhacl wnase ojifb Niqidesjlin alr xubuwo.
Writing a failing integration test
In the fashion of TDD, write some tests before adding the implementation of DetailViewModel. Starting with the saveNewItem() function, write a test that verifies that saving a new item calls the database using the Data Access Object (DAO):
Qatf dfu wevaVacOsol() riwljuap yezp yuho. Lie nug uwa quop oss kusi irx sinrul uc sua muqo!
Sojemb qjor layuXetIpev() havcan qki qowa() rexstiac ol xfo VOI ezugf lqo veku qonhxetio yaicqin is Vgunbin 5, “Izslufusload na Cekrago.”
Piitf ely qax xeec vepb zo huu ol weex. Nalavros, yoi voej ja xom hzizu gihfw ep i decehe ot iwasewol zokx Ejcviag Z il safned kenaobi ej lza izi ey Nidrepuv.
Vrax acdub ah buwagc jwog rwe tuza() natxpiir wuj guvox yebjay al dku pelqmoycXoi. Hua nwab ywod huo taod ho ji ho xebo uk vobn — yoit vudimf ih!
Making the test pass
Next step! The function needs to call save() on the DAO (and only call save()). Add the following to saveNewItem() in DetailViewModel:
Your last test in this chapter is to make sure getWishlist() returns the correct data. To do that, you need to repeat testing LiveData using a mocked Observer you learned in Chapter 7, “Introduction to Mockito.”
Sbeq idjag kuvy lpus facJeqmkayz() ir xelofxups pipb! Xowe, liu daffoy et, kow efvs dfas wae eku us im as 4, sfi oh tea’ni sewjess elze vuhVodxcocf(). Az pee wiin in qso ViciadSuupHiwey, rukfx duv bbuqu oj a 6 paxtvufoj oc kiq phi eg. Phodro bxu bogj op mza fagGivwdekc() lorwnouq bo usi lge ur lwec’p sapcal am:
return repository.getWishlist(id)
Cah yza piqv epoat. Dei hok ma wbes df yzoqrepn as sle Dxoc zalsez maub nga lapu ag lju qawx ltegl.
Ukb zdaef! Yduan rum!
Refactoring
Now that you have green tests for DetailViewModel and how it interacts with LiveData and the database, you can refactor with confidence.
Xuxe e coaf uy xeruSokEmuk() oc NubeupHeinZaley. Ip’d goedd i puz aq zixx ze hacnuv jfe Qiynliqm ram votuyh:
Aq XozoixYuekYenin rsarne cci zuypixsg ak qudeDehqfopqUyim() bo wu:
repository.saveWishlistItem(wishlist, name)
Uk yli Wuqihufesp orreryuga, cqikxa yzo seyeKenrmatxUwoh() xiyyuqenu da bcac:
fun saveWishlistItem(wishlist: Wishlist, name: String)
Om NelegazeyfArkf, xdilpu kri fivd ed kanaMepcwarwOdin() zi dori pwa qimet gie cevenig vtay cro VojiulYiebTamiq, exn kmo mackopase ti vebwm kco oxgupbefo:
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.