Architectural Skeleton - Testing on Android - Part 9

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys welcome back to new video so in the last video we created this fake shopping repository here which will be very useful to test our view model that we don't have yet so what i want to do in this video first before we test our actual view model is to create our architectural skeleton so that means we will create our three fragments that we will have on this app on the one hand our shopping fragment which will just display the list of shopping items then we will have an add shopping item fragment in which we can add a new shopping item and we will have an image pick fragment in which we can simply search for images in the pixabay api and select one of these images to display in our add shopping item fragment so let's actually start to do that let's create a ui package here in our main package um called ui and inside of this ui package we first want to drag our main activity into that ui package click on refactor and then we are going to create a new carton file class instead of that package which will be called shopping fragment select class here it will inherit from fragment of course and we can specify the layout resource for that fragment which is our import r here dot layout dot fragment shopping then we can copy and paste this fragment this time for the add shopping item fragment just swap out the allowed id for fragment add shopping item and paste it one more time here for our image pick fragment and press enter here and swap this out for a fragment image pick okay so the next step is to create our viewmodel and in this project we will actually share one view model of all of our fragments so i think because that is not a really big project here that is totally fine that we use the same view model for each of our fragments if you have a bigger project then i would recommend to have individual view models for each fragment but in this project that should be fine so also in our ui package we can create a new carton follow class select class here and that will be our shopping view model press enter and that will inherit from viewmodel of course and now we actually want to inject our repository into this viewmodel so what we will do is we will use daggerhill's annotation at viewmodel inject constructor and import viewmodel inject here pressing alt plus enter and now we actually want to create the repository here so private valve repository which is of type shopping repository and now you can see why we actually created that interface in the last video that shopping repository interface because now we can specify that our shopping view model just takes a shopping repository as a parameter and not a default shopping repository because if we make it like that with that interface we can on the one hand pass our default shopping repository here in the constructor and on the other hand we can also pass our fake sharpening repository for our tests in the very same viewmodel so we don't need an additional viewmodel just for our test cases next i actually want to paste a class here that is also very useful very similar to the resource class we had in the last video this one here um we will have another class here called event so maybe you know that i will just paste it here because that is again a class that is um the same on all of your projects and you will see that is not very complicated that class but it's also a generic class and the purpose why we have that class is to basically make our live data emit one-time events so we often have the problem that we make a network request to our server and then with that resource class we either emit success or error in the end so the actual live data object holds either a success resource or an error resource and the problem with that is let's say we emit an error resource and we show a snack bar that an error occurred then if we rotate our device that would mean that the live data would automatically emit again and we would again show that snack bar even though the event already passed and that is why we have that event class here so we can basically just create a generic class with some content and it has that boolean has been handled which is false initially and that means if we call this get content if not handled function that will only return this content the first time this function is called and afterwards you can see has been handled will be set to true and if that is true we will simply return null here so only um the first time we call that function we will actually emit the content here and if we call it the second time we will simply get a null response and if you've never used that class before then this is probably confusing for you right now that is fine you don't need to understand that right now but it will definitely get clearer when we actually implement that in practice but we just need that class here for the live data objects we create in our view model right now so let's actually go back to that view model here our shopping view model and create our live data object and our function signatures and yes i only create the function signatures here because as you know we apply tdd principles here in this tutorial so that means for unit tests and the tests for review models will be unit tests they only test components of our viewmodel and not any interaction between fragment and viewmodel so because those are unit tests we actually first implement the function signature and then we implement the unit test and then we implement the actual functions so that our created unit tests pass so on the one hand we will just have very simple life data objects here for our fragment that is on the one hand our shopping items left at us so just the live data that emits the list of shopping items from our database so well shopping items and that is just equal to repository dot observe all shopping items then we will have another very simple live data here for the total price which is equal to repository.observe totalprice so for the other livedata objects we will have here we actually have to write some functionality so first of all i want to create a livedata here for our image responses so if we make a request to our pixabay api then we of course get a list of um images that matched our search keyword and we want to um have a live data that holds that list of responses so what i will do is i will create a private vel underscore images and that is also a best practice you should use here that you make your actual immutable lifetimes in your view model private so you can only change those from within the view model and then we will create another live data which is just a plain life data object not immutable live data object which will set equal to this underscore images live data and that is immutable so from the outside from our fragment we can actually only access the immutable live data and that is just the best practice you see everywhere in the repositories by google and by other good people so first of all we actually want to set that images underscore images live later to a new mutable live data of type event so here you can see our event class comes into play um after the event of type resource of type image response and we just call the construct on that one and now as i said we will also have an immutable life data here which will be a public live data so well images without an underscore and we said that actually we need to specify the type here which is live data so not mutable live data just a live data of type event um resource image response and we just set that equal to our underscore images lifevideo so that is the actual life that we will observe in our fragment and that means since we explicitly declared that this is a data here not immutable live data that just means we cannot post a new value to this live data from our fragment so we can only post values to this from our view model to this live video because that is private okay so what else do we have we can actually copy that those two lines here paste them below and that will be a live data for our current image url so when we actually select an image from our recyclerview later on after we searched for images then we are just interested in the current image url so the image url of the image we clicked on so that we can use glide or image loading library to show that image in our add shopping item fragment so that we can basically when we create our actual shopping item that we can attach that image to that just created item and for that we will just have a live data object here so underscore current image url that will be just immutable live data of type string so the url and that will be current image url without an underscore also of type string and we of course don't set that equal to images instead to underscore current image url and now we will have one more pair of livedata objects here make a little space actually which will be underscore insert shopping item status so basically we will have an insert function here in our view model in which we will just validate the input of all our edit text so basically if the name is valid if the amount is valid and all that stuff and depending on that we will just post a resource status we can observe on in our fragment so that will actually be a live data of type event resource of shopping item so the actual item we want to insert and then we can copy that paste it here without an underscore and replace this with shopping item again and set that equal to underscore insert shopping item status okay so and now let's come to the functions of that view model here on the one hand that will be a function set current image url which will just post a new value to our image ul live data and that will take the url as a parameter which is of type string and actually that is only a single line here so in this case we don't just leave it with the function signature here instead we will just use our current image url with an underscore and post the value url here and then we will have two functions on the one hand one function to delete a shopping item which we will pass as a parameter here and that will also just be equal to viewmodelscope.launch and we use our repository to delete that shopping item and we actually already tested that functionality to delete something in our database so that is also fine and the same for inserting an item into the database so without without validating the input just inserting an item into the database after validation so well insert item or insert shopping item into db also pass that as a parameter set that equal to viewmodelscope.launch in which we just use our repository and insert that item then we will have a function insert shopping item so not into the database right now that is the function that will actually validate the user input so that will take some parameters on the one hand the name of the shopping item on the other hand the amount which is a string here so i will pass that actually as a string so exactly the string that we just read from the edit text field and inside of this function we will just validate that and then afterwards create a shopping item where we convert that to an actual integer and insert that item with this function into our database if the input is valid and we will have the same for our actual price so price string which is also string here and then we can just open up the function body here but as i said for this function since this will be quite big we won't write the implementation right now because we want to write the actual test case first and the same counts for our last function instead of this shopping view model which will be a function to search for image and that will take an image query which is a string as a parameter and that will just search in our api for images and we will also leave that empty for now okay then let's actually switch to our constants file here because i want to create two constants that we will need in our viewmodel later on and we need those constants also for the test cases so on the one hand a const well max name length so the maximum allowed character account or shopping item name can have which i will set to 20 and we will have a const val for the max price length which i will set to 10 so we allow prices with 10 digits at most which i think is actually enough here you can increase that but actually if you're not a programming youtuber then there is no way somebody can afford that okay and the next little change we need to do is in our di package in our app module um we actually don't provide our default shopping repository for our viewmodel normally we wouldn't need to do that because dagger knows how to create such a default shopping repository because it has that dow object and that api here which it needs for that but since we pass such an shopping repository interface in our shopping view model constructor dagger will actually look if we provide such an interface and it doesn't know how to create that so what we actually need to do is we need to write a provides function here which will just create a default shopping repository and cast that to such a shopping repository interface so actually add singleton and add provides function provide default shopping repository which will take on the one hand our dow which is of type shopping dao and on the other hand our api which is of type pixabay api and that will just return a default shopping repository which will take our dao and our api and as i said we cast that as a shopping repository now so now we can actually just instantiate this viewmodel in all of our fragments which is the last step for this video let's start in our shopping fragment override on view created and create a latent var viewmodel here which is of type shoppingviewmodel and in here we will create that view model by writing viewmodel is equal to viewmodel provider which will take the owner here we pass requireactivity because we want to bind this viewmodel to our activity so that it survives if our fragments are destroyed since we share that view model between all of our fragments and we call a dot get shoppingviewmodel doublecolonclass.java then we can actually copy that line because it will be the same in all of our fragments okay we can actually copy this whole block here and switch to our add shopping item fragment just paste this here go to our image pick fragment and paste it one more time so that's it for this video we prepared everything we needed to prepare to test our actual view model and that is what we will do in the next video so please if you enjoyed this video give it a like comment below what you think about this and also if you if you haven't subscribed to my channel yet then quickly make sure to do that click on the subscribe button it's only a single click and you will get regular android content every second day see you next video have a great day bye bye
Info
Channel: Philipp Lackner
Views: 22,816
Rating: undefined out of 5
Keywords: testing, android, test, test case, junit, mockito, mock, fake, stub, tdd, test driven development, intellij, android studio, unit test, unit testing, integration test, integrated test, end to end test, ui test, kotlin, mvvm, live data, coroutines, dagger, retrofit, room, database, roboelectric, android test, jvm, flaky test, development, programming, git
Id: x2WahC3N_Yw
Channel Id: undefined
Length: 17min 35sec (1055 seconds)
Published: Sun Aug 30 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.