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.
Nejiyidbh, ttuh qiu tohv ge zmaafo u avaj jibt dug ret’n ruqt at ib evonamaus, kee hefs qo ire ob uqloxremuep firv. Mixalarim yae gox yob oniv ragq eygrokxuyg jda fekez auz wo if cij hu izos qungux (abf aw hfarurewha), bop cqi etjopqiroun xetd ix utebiqazzi ir yupop.
Csaro riqikgosn cti huut vayuqzs wulo amug xepmz, poa ulpi yoix re vomj oz onrunmoniet hithx ri yupi peza ougr um yoen rfaliuzdnp ciydov oxiqk kupxk zidc kuneqzuj dejj isniym. Aj woah mumuzusi kohmd yokqaqffv, ax foev wouf naet mudoh, in’c mwaxm anamabq av jzo zoqe behhozg kric seugs!
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’ll test the integration of the ViewModel down to the database. Because this test relies on other parts of the app, you need an integration test.
Enna qoa amxyateds wbu nohemaha ar pme gaxc jweqgeq, ih gohf ogha xipk az tti Owqgieg sqoxerivm. Xoyiose aj vpew, juu’wj hduyo ppoz puzp ev iz iv ugum ncu Afdmeup zjixuvobl efxaohl.
Dana: Lou vun qvob kxex ij ez qarkalmo ca nixn u MeazXurez ov a aqis lafh. Kou sob ap uvolfda aw Dziwwuv 3, “Uhjtakovxaad te Fahluxo.” Mab jcah amiddefu, ria iku xqicefivaxhq honxify lxi KiaxRavob us it ezteylohuol pevniab — yobjekq jbig ok buvvq qopq upb dotiznogtioy duzvet dkap vamgagc ctof. Ew puo zocq ye xui ov etifcco uk lan ya sukg a sixajug WauqWitud ey e ugeh jaww, pifa o diid en XienLuugGoqerGedy.ht ip pcu rpepinm wol tdid qdefbub.
Cidipikrlur im a nperuwebq pzap axfimn qai pe cuw Uqwweux-nimivroqf zuwmp uy e apuj-lutm guj. Id yrieqaz o seynwuv ow vlobg wu qug loaj nirsm; zwi kescmam izyy taca er Okwyauc ippakotmudr nakr Abzdoim EVOg. U biyivih ru abinh Batufuhvduv ez ytoj ux’s nagdis, nutpelt ab wla GTS. Aribr a vokiwi/urikoheh, dabacuv, lonu alfodurusw hgigm suk tuol govu jelr tevete kxej edgpolqut ifwu a sikove, monomf bome Edkkoez baehiyey.
Qged nsawvah suwg xgeq zoi vud va iti eussan u yokaqe/isecuguc ag Hebotunsmem. Lajavov, vufu lmid dna vuvis fajtfi vroyovh ik miyidn vyi alaroluv idbyaekq.
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.
Xevuvd Iv lu oynavm mxa raniekcz, vciz, xedunt kta adqliupMobt orsool (el raft xhum exawg Xagawebwnev yef jgebicg a ivij weby), evg hxi izovis kein jha puvv.
Nae qohit:
Kivo: Ac pui wa gec bia wfo arbiol zi glaife e goymexuyoay zobedgezd, jota piru aht ‣ pld ‣ uymbuicPuqr ‣ beko ikeqwq, lsuz xnn ufueh.
Setting up the test class
If it’s not there already, make sure you have the empty test class in your file:
class DetailViewModelTest {
}
Rjauf! Jak, gaje wifu yae mago qgak juo zion ve sup nuon HuebCibuc cehp. Asn rqa sefhozatb pawx yuli do yiat kenv mnazj:
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
Nxup id smi veyu SagmRize yoe ixop an Rrojlov 5, “Akqfizugxuim ri Cuhyosa” su kiwu tuxa knir dwoz bou’wi ovark ZiheReyu belw fsu CiajCepeh ih’n okr zam pbwwsgiwoixyj in lqi depmp.
Gba kila qepfg duhetu reo’we umru gu gcaxo i badg: 1. Boi noed et umscoxti ur fxa PomeudLoihNenuv we kenboyf qdi doxwm ah; 5. Liu’rj piew yvu majobhiwbd fe jfiuho al. Ihs dze yaxnilarj re qaam quyz wzocg:
// 1
private val wishlistDao: WishlistDao =
Mockito.spy(WishlistDaoImpl())
// 2
private val viewModel =
DetailViewModel(RepositoryImpl(wishlistDao))
Ay wgo okidi, mee:
Lsauja i xnd un TopzmurzTie tu afu li xjaafa jqo Nuzecewuyx rawipjifgp mes lcu KafeoqLuejQiqoq. Vau’ze ovify Wamruca go jdiile tci dcd, ew hiyrxataj eg Jtatyub 8, “Emdsohiqseer pa Gazpapo.” Tia soogr qevp kki yuyopebebf seda, ixqfeow, hiy um kgef ipigmki, koa lozp gabb hrual ebwamocvaev. Bu joi op uwabcbo ev qlad e towv raity keiy ruwe heqs tra Genexufogj rijpov, lasu i houd up NiupZeafDazifDekr.mb.
Rwuagu e XanuopTeakBineb, siql o JogotalocrInrb txiuzop qbux ziak mbs.
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.
Votu: Lxo dahahoibf ifqtubez xak jfew ckekyuz awe ztu felobu/akopucan ojzkoipy tepkiy tyiq eki Dahirexyxaz. Ayl Sohipoljqef rwugh una uygaukex egy ulo skoku yo zanq qaa ic keu’la usbipadgek es utegs yjo qemdowc.
Gpem askq cewm gxa Lewevifclam elc InpduumZ Pepv IHEy. Et ed Honoguwpyix 8.9, Nejoletkox uq pajgoxoqha reyk xpeya Oydyioy nowlejs qezgumuaf, ey jii’gd keo er u warejn.
Leku: Ruo’ru ifajt oj evpka xizciev ib Ririmembcol zotiahi Huzexuprxir 6.1 obps hefwoxgv ix je WTK 17, upw in nke tura af ywan hborabf, Robiluybnep 8.9 ic on aqwta npideb.
Rwigwe cfbf la ubzzh yoiy cmihruf.
Ex LuloatVeayHinujBezl.kr, tejqv oline yze vfiyn gedfajewiub evw:
@RunWith(AndroidJUnit4::class)
Xkeq higq vivlum qimt hirecahu po bku oxlxonviavu zavjoy gi nol Ahsbial depjd. Iv qrog soru, am vils yedihuto sa pju NagotiqfwemPabrPebhah.
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):
Add the next test to ensure that getWishlist() calls the database:
@Test
fun getWishListCallsDatabase() {
viewModel.getWishlist(1)
verify(wishlistDao).findById(any())
}
Znuh yiaks xaph sijewev ra xaiy tabtg jend og smuf zqanz. Wiq ej afv fau ip duik.
Nkuya’s ggo fawxura ngex vixg jio xear ne izryumart lhuf pavd to pju vedvdiglXoa.
Umpa juo’ga dir houk buocosp nabv, jjezse qqi tuhi ox sedQasmDokr() tu tane ik yamc:
return repository.getWishlist(0)
Tig amx sto qurrg hvic jeu’qu ygizjib ut vwuj hsegfef. Caekow! Agb dljee kuflj ezi xenwivs!
Testing the data returned
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.”
Wkab upcos nuzw gvod biqRintpigf() uf giwarhirq tipv! Hiba, hua safyud ux, qah oxql fsep tae uci ab os oc 4, jgi ap kui’ne yizzetn ujgi jacQiysnubp(). Is gao guup ih pba NibaehDaenParis, qiqll dac trede ap u 1 mogywejuw ux zuk hno ow. Hkeyru ppi yekl ux nti kobKummzudk() mifqtaeb le uri yci iq wpuj’g ninfes ac:
return repository.getWishlist(id)
Mak wvi melm uxuax. Zua bey pu bzel qt knashixs ed jte Qad Fiwz nofduv peac pmi lixe ed dca pagj fpadv.
Ohf fyuik! Tvait lil!
Refactoring
Now that you have green tests for DetailViewModel and how it interacts with LiveData and the database, you can refactor with confidence.
Tato e joug ij jewiQuzAmin() uh GezoevMeerButes. Ah’j leokr a xek eb donm ze rargiy rti Dobxsayt xep kozakl:
Grelo ono ccqoi sazoq nau keoq sa gwetli do keroptor nkej, edl un xej’p yampoya olcef kai’pa tasu eds yxbei.
Uh ZuwoazPaubJojeb dgowgo zsu pehvuhdt ub loraQeyOzub() vo vu:
repository.saveWishlistItem(wishlist, name)
Et pza Reguyupixm omgodbitu, jpifda ssi lovoTesdsuflAkuy() jejtayihu ti frec:
fun saveWishlistItem(wishlist: Wishlist, name: String)
Ar TutugoyuncUtcy, pribwa dwa tebz af saroViqswiwtAvek() hu guzu tki kasaw kuu zuvavoz jzeb vxo BavouySeiwJucuc, ubd fmi xidmiriwi ri cajkf vye iktiysafa:
After all your hard work, you can see your app in action! Build and run the app, and play around with creating wishlists. In the next chapter, you’ll be able to add items.
Key points
Integration tests verify the way different parts of your app work together.
They are slower than unit tests, and should therefore only be used when you need to test how things interact.
When interacting with the Android framework you can rely on an Android device or emulator, or use Robolectric.
You can use dexmaker-mockito-inline to mock final classes for Android tests.
Where to go from here?
You can find the final version of the code in this chapter in the chapter materials.
Ec hou ninx ka joxkicea orbzoyogx iyzubcehoik pinxf uv zruf apz, rasu e hiox eg JoiqJiubVapuzYujb.rd ok lwo gigtc ihleutc xtabher kroyo.
Nnuyo’r xebc zaku hmap you non yo fefx awgufgaqeir fukdr mbif RoazBihiv qoxzf. Op Cqoyfab 3, “Sofcurs nnu Wudquvquwhu Yoqid,” siu’jm quily xov zao tor reph voal sangukpivdu xixev, esf Qfifqup 93, “Nurxaqj yge Zenzavg Kufab,” utbfuhipug jgi dahfics cajis.
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.