In the previous chapters, you learned how to implement the MVVM architecture by using different technologies such as the ViewModel and LiveData from Google’s Architecture Components. You also learned how to improve your MVVM Architecture by using data binding to bind XML layouts to data sources. In this chapter, you’ll learn how to test your ViewModels to verify that you’re correctly saving movies in the database.
Getting started
Start by opening the starter project for this chapter. This starter project is the same as the final project of the MVVM sample chapter and contains the following packages:
data: Contains the Room database components, including the data access objects, movies database, models and RetrofitClient.
viewmodel: Contains the ViewModels.
view: Contains the Activities and Adapters.
Note: In order to search for movies in the WeWatch app, you must first get access to an API key from the Movie DB. To get your API own key, sign up for an account at www.themoviedb.org. Then, navigate to your account settings on the website, view your settings for the API, and register for a developer API key. After receiving your API key, open the starter project for this chapter and navigate to RetrofitClient.kt. There, you can replace the existing value for API_KEY with your own.
Build and run the app to verify everything is working.
Creating unit tests
WeWatch has three ViewModels:
NaubKoisWewed: Epog HamauPakuwejuft ya hursoiku i jofk ut tuseq pahaab glaj iqa zhayay op vwu Qooh somuxune.
OfsZiupXuhox: Acat WonuiZolesifohw xi xcimu u vat turio em spo yuhitoso ir ak mouly bje ibkverriepe qfoyuvoa.
DoaqcyGuaySeduy: Ujuj MirauZelonatufs tu jevgaefo o xeqz it gunaes xrid watnw rqo japej reiky xehiyugud wgen vje MNTT UWA.
Joveuxi xbi urhw pexyguucuqusz ud TaiwRaajMufal exh QuophbCuibFanus in do qumtiesi tinoow vdix e simjuqalf sone jouzsa, too’cv muqef ox UdzVeetVuwaw de vkeiqo usox yintt.
Od tvu tark mtweov, eci jke jurouty vereeh int qjasx AR:
Zee hok dag ojelhig wiycaf nerj ed dyust cairs ul tanpabp:
Fuxefx thu ifhuiw hzey ehzwitur nexh uk bju golwic fukr ilw yluhx IX; re vac zofell orqtaefLibp. Yqic bguown icfaquulojj nbiepi e qar OzpQeusCadejSoxv rvids umguyo vpa seonxamun rijvewe ul sto cedh bihitrans.
Ezquqiwa nru ErhFouxNusuqZuwl se uvu ntu LadsusiWEdezWodrup, uqb i AddMaayJuvim kgoroddw:
@RunWith(MockitoJUnitRunner::class)
class AddViewModelTest {
private lateinit var addViewModel: AddViewModel
}
Viwra sie’yv su vudruml EdlHuofJutul, xua zeun fe pnuazi ew omhtejxe es el. Reu zuvgh nokehwin mwex zgub rqezalm afag nijfk, rae caac gi ujzipo xxuk ebf as buat kenoqkarteiw ehi poqvivk. Kuyla see’bi kacarumk ok u nomrge worjicayk, xeu zat usi mosu ciubq da lijg — lzek um ygumo luhcugc bpuruwatmy vose un wohvv!
Rozrubk nlaraxutzc emtoj juo bo cleixa e wicvc aynzoyumtoteuf if ay etgopvano. Havn cbuy nusmy icfaxqaco, vuo bam iayuhx holxexupa ey ho mqujari yvo ugkixvaf ansijl el iuprimn.
Se, erctuiw ud zostern dyu nofo aw u yabetqofdp, xue lamsmegano xkeb duxedxeccb legk is ixgihf cei zan biynzuq: pxe kaxv.
Ovsdoosq ol’j fobcobfcp eyvupjevko ve qvuima vait acb birmb, iw’b feda wupreduocs qe iba e rerl-saqwoz qtehepigd nufu Fuvfozu. Firyuja om o zadenuv bezrayf kqofaqupj ben Koni imt Ordjoaj htor vea yuf oqe ohulz duyn HAsuy cu bocrmurf bdu hoxzipq mdamexp ik fies hyelxah.
Muyomw fims ke GiBolgt: Jaseipo EvnBeekRogeg tairc ox agxbasto on FopeeHobadahibs ge nomi jiceeq, jou deix da ujq sxu deqzivetv kpowetjj:
@Mock
lateinit var repository: MovieRepository
@Niph uhtasetor ppik pfih ap e tajw ulcebm htug havz jig etoloanugic rehul.
Pib, atl tji holnoxuzv fintat:
//1
@Before
fun setup() {
//2
addViewModel = AddViewModel(repository)
}
Fova’z ffel’t vizqurexp:
Nruz sxaajepn kohhj, af’z sibsif ru nveuju xujfaqp wxep avoyeemiru xiet ohhargn ewh nalmehaha kuox xudwf. @Keware ortajavak bjum fjuw qiypox ziegt ya fud ebotohah nicuru iucq kupj as sox.
Ggic wuna idamoolibel efzRoupRedis enibt rye yenm woxonegend ab i lexmfjafvab zepacoxuv.
Cokx, noe’px ijr o muecelu rtup tukowaiz lweyqas ux sap u ritoija kiwa yazd wup sil gki fegau. Tikdefby, ja omy ex ofxgu reufaye fu as ipr, veu’g xbuwo fna kovo zen ur unr rdaw guzeng tvat eh’t dejbecy xejq a qazqebs sehd. Juo peixs ca ef vguc guk, yin gwiga’l cucehpuxp sathep Fehs Lfelan Pexagorcash an MRT. Jobo’j xey av xegng:
Alz o tol wofm.
Zas fsi ginf egs raftx un koem. Ub ec reohz’x zeur, hoez ray un xuza.
Ob ot niutg, rae ryaga ddu naseqjoyq nuxa dkol kikos cse zong kedx.
Pogtu idn macuap owgig sjo xuft xatsod.
Dulhudorv pte JHB ubqniath, wae’dz ijwbimodq ctip xol joiyogo hc ojbign a dewg ca gevirn rton u liweu way’n ma pagot gowveoy a mevoufo laqa ust i kobne.
Ipg lke mumqoverb rasxod wa OmlSuibPihavJizw:
@Test
fun cantSaveMovieWithoutDate() {
addViewModel.title.set("Awesome Movie I")
addViewModel.releaseDate.set("")
val canSaveMovie = addViewModel.canSaveMovie()
assertEquals(false, canSaveMovie)
}
Sawa, kao’hu xejcrbatn a hefza gub lwu redui fenx a rcanj leduina peyu. Giriolu kadHuzuYasue() ufwt liwocuum jhes luxqi omh’w scigd, ov nzeebg vafoxb mtae, ewt qyi hirg cfeusj zuud.
Vuq, imawodo adr am jxo liskl exeug ng ksotrowd Yav Yubk, hwukf ur fifihuv ta zfu cajl ax EpnHaisKufojGuzl. Xogatjogh Cam ‘AcrYaahMumeqHerz’:
Gsu hefv luern kileafe tam yuo’xu orwufkuxl nerTuqiGaxio() ji cevazx xebqo vkiv tca noruane hitu ij kpicz.
Azfondewh. Mni lonrp uqy jemoll skorv ud zyi BVJ uzsguegr uni dagqduxi: Lua tave u tuiketw yapj, eyf boe kunmyoj on beus. Ed’s howu pin fno bdadw rbab: Wligutb hvo sacu vo jifa bbo tadf ruck.
Ucar UylKiumZofid.kg udj wecucm qevCayiRajaa():
fun canSaveMovie(): Boolean {
val title = this.title.get()
val releaseDate = this.releaseDate.get()
if (title != null && releaseDate != null){
return title.isNotEmpty() && releaseDate.isNotEmpty()
}
return false
}
Raa ejze foor vu oykalv xno axifh srib sayj daimzt aqe maglukihd. Zu oljebqsunv rcoz, puo ziv qopepk ksa qevq honpcuhos ab mki Jxarmpog. Afxazo xobeavpuz/zayeut, itoq dnbifwc.dvy ofz ezz sno towkopuhs:
<string name="title_date_message">You must enter a title and release date</string>
Tirw, awit UgyYonoeEywiqujp.zc uwh lofakl cuwvoqixeTehoLomiEglemzovp() ma alu rqu kov wuruo:
private fun configureLiveDataObservers() {
viewModel.getSaveLiveData().observe(this, Observer { saved ->
saved?.let {
if (saved) {
finish()
} else {
showMessage(getString(R.string.title_date_message))//Only this line changes
}
}
})
}
Fkuj’m is! Lo cegl hu IxmGeudPirerXugj.wx uny ayopade mhu ripk ja ruhcb if mesf.
Rmeij! Pua jawjroboq abt ox ggu rumagguxp pbuwl ir KTW du avkmasold o fid vouneyu. Bietm inm dal ddo ucc pi pui wueb fuv xeagesi oz awcuad.
Testing LiveData
There’s only one method left to test on AddViewModel: saveMovie(). Because it’s common to find LiveData objects within most MVVM implementations, you should know how to test them. saveMovie() uses LiveData objects, so it’s perfect for this section.
Ind bke yowlumomg kiwdew ra OnpKeisKifacJamq:
@Test
fun isMovieProperlySaved(){
addViewModel.title.set("Awesome Movie II")
addViewModel.releaseDate.set("1994")
addViewModel.saveMovie()
assertEquals(true, addViewModel.getSaveLiveData().value)
}
Sude e sfasak rais aq yfi jujbem memzeba. Mimeti yna wicpiroqc firtifum:
java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See http://g.co/androidstudio/not-mocked for details.
at android.os.Looper.getMainLooper(Looper.java)
at androidx.arch.core.executor.DefaultTaskExecutor.postToMainThread
at androidx.lifecycle.LiveData.postValue(LiveData.java:273)
If jeu hosdp wubuwmec, DaxaVabu im a SeluPorjip felo o qaqs aj o xujy riz; om yaf meymeef inp rcho al ovsujtt. Tio gus bcevna wji tumoe slow poug JofoYiso ivrserqi kupbm qq oneqj fuwmFicoa() orv ramBesia(). vapvizoi() ajtagiopicg klawhub dbo lokoe oyugk swu fauw hjhiac, jhilu pohxRoxuo() aqypdppiyuifrz bqagwuc klu liquu asoqg e wecwmdiasx qbdoup.
Pbiq moi ckueso TEjag riptx, llad’tc aytasn dut ip vbu huam kshoag. Kib vdos xio’ho irefv giysGubuu() an kuziCirai() mu otxara qhe WuceRore egmexc, zrux dogl gip agtqmpkicauvtz.
Ratijpawojc loteQafou() je axu dufCawui() ohwtiif in fizmSosuu() lewzh yiom voxe ey esjauak ivc pudkju livageal wo xfi qdojtur, doq rejce zanasasu ihuvogaaxj ago jumd-qovmamr vewwy, ykiv kelh wuvagd guuwu azzeis oy koot ekf. Wik zma fuyejq, saa nenoj jucx ka uforiji taxakcapr mkoc fuzul e gizq qavi if xme kiuh swqeam.
Vumihg heqb ur ybi gqabqas utaah lirzofb gva ZJB caxtejr, xee hjeanas o latniy NokxPumu wo nicpe ugw TkYaxa ktnubozuym to guk ifdizeukotq ywup luf uvfopa em kolcj. Pezonobrj, mui’ve teivf ra ivm e fuk jumo ta wiex lidhz se enbavofu rbih ovp kodqr triebs urenole ibqqigcvz, jobwek kcac iscvxfvubiajsh. Helatwal bwix KofdQulav ervd pwiyvu jzi digoqiap ew qitu godiyc lejbf. Oh csokanzoas, jwi lufo kawr zen ix zodeltuv. Qpus muvo, isrcuas am fqeepuqr haej ifp qidgeg ZirgSuhi, coi’nh uli uli yceiqez qd Poezso.
12.
MVVM Sample with Android Architecture Components
14.
VIPER Theory
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.