Android Testing ViewModel - Common problems

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey welcome to this video so in this video we're going to talk about unit testing your view model i'm also going to talk about one of the main issues you might face when you're writing unit tests for your view mode so here we have a simple e-commerce application where i'm going to use it to demonstrate these concepts that i'm going to explain here and you can find the repository for this project in the description of the video so let's do it so this is the view mode that we want to write the unit test for so it's a very simple view model the only thing that is doing is fetching data from a repository product repository so we show a loading state we fetch the data and then we show a content state so the easiest way to create a unit test for review model is to click on the class name and then option enter on mac os and then you see the option create test and then already gives the name for you and then it's very easy to create the test okay so the first thing we gonna we're gonna do is to create the target of this test which is the view model itself so so let's create the instance of this view model and this view model also needs some dependencies so in this case we're going to need a product repository it is a good practice that you don't pass the real implementation of of your dependency because if your test fails you want to make sure that they are failing because of the view model and not because they are of your dependencies and therefore i like to use a library to mock those dependencies there are two libraries that are very well known which is mokito and mock k as in mock kotlin so i'm just going to create a repository and then i'm gonna do okay um very nice so now i can write my first a simple test so let's call this test when fetching products content state is shown so i want to verify that whenever i fetch my products i end up showing the content state so that's what i'm trying to do so i'm gonna need to call the view model load product and here i should pass some id i'm just gonna pass a any id because this is a test and then i want to i want to assert that viewmodel.viewstate.value is content very simple test i'm calling this load product this is going to launch your core routine it's going to show the loading state is going to call this method get product details and then it's going to show a content so i want to verify that i'm showing the content after this function is executed so the first thing i have to do is i have to mock the respon the response for get product details so here in the mock is very easy to do it you can use the co uh every and with that you can easily mock the response of a suspend function so in this case is get product details and i'm gonna use any here which means for any parameter that was passed to the product detail then returns another mock object because i don't really care with the return type at this moment so very simple i'm mocking the results here and i want to verify that content was shown so let's run and see what happens okay so we got an error if you take a look in there you're gonna see that it tries to call this get main loop looper and this looper was not mocked so what that means is that it tried to access the main thread of android but since the unit test doesn't have access to the android apis doesn't have access to the main thread fragments activity context it doesn't have access to it that's why unit tests are so fast because they don't need they don't load all the android dependencies and because they don't have access to the android dependencies they don't have access to the main thread and if we take a look in this in this method we are launching coroutine which is going to use the main thread the viewmodelscope and we are also trying to post a value in our livedata so that is also going to try to access the main thread so that is not going to work so this is one of the problems that you might face when you're writing unit tests for your view mode so let's try to fix it by the time that i'm recording it there uh one way to fix it is to use these rules so there is one rule this that is called instant task executor and there is also a standard test dispatcher so your coroutines can use this dispatcher and the way that we can fix it is that we can create a setup function and in this setup function we're going to say that dispatchers set main and then i use my test dispatcher so what i'm doing here i'm telling i'm telling the coroutines to use these test dispatchers that's basically what is going on under the hood and here is the same but for the live data so now let's run and see what happens okay so we got another error and this time is assertion failed so if we try to debug it we are going to see that this viewmodel.viewstate.value is actually new at this point that's why this assertion is failing and the reason why this is failing is because if you take a look into this standard test dispatcher in the documentation it's going to tell you that it doesn't execute the tasks so you have to do it by accessing the scheduler so what happened the reason why our test failed failed was because we called this method but the tasks they were not executed by the dispatcher so what we have to do is in the dispatcher we have to access the scheduler and then we have to advance until idle so now that we do it it is actually going to execute the the tasks and then the value of the live data is going to be is going to be there basically and now our test succeeds so those are one of the main issues when you're writing unit tests for your view model you have to remember that your unit tests they don't have access to the main thread and since the view model is very often trying to access the main thread you might have some problems with it so to try to fix it you can use this rule and also a standard test dispatcher so now let's create uh another test so now instead of checking if the result is content i want to check if the loading state was shown before so when fetching products loading state is shown before content so i want to verify that my loading state was shown before the content and if you try to uh just verify that here is loading then well of course it's going to fail because the last value is a content and the live data it it is an observable and if you investigate how an observable works it doesn't save the previous values so it only saved the last value so if you try to verify that the loading was shown is actually going to fail because the last value of this live data was content and not loading so what you have to do is that you have to somehow save all the values that were posted to this live data and then you can compare those values that you saved so the way that you can do it is by saving in a list so let's create a variable that is called states and this is going to be a mutable list of product details view state and now i'm going to observe all the changes that happens to my live data so viewmodel.viewstate observe forever and here what i'm going to do is i'm going to add all the values that were observed so now i have all the values and all i have to do is instead of checking the the live data itself i can check my values so here i want to check that the zero is actually loading and that one is content so now so let's run and see if it works nice it works i always like to see my test failing as well just to be sure that they are actually working as expected so i'm going to change it and see if it fails and it fails so now i'm going to go back to the previous state which is the correct one and i'm going to run all the tests of my view model and as you can see all the tests has passed and now we have a working unit test for our view model so the key takeaway here is that you have to remember that unit tests they don't have access to the android apis so the main thread for example is not accessible via unit tests and that's why you might face some problems while writing unit tests for your view model if there are other ways to unit test the view model make sure that you leave in the comments and i'm definitely going to take a look as well so thanks for watching if that was useful for you hit the like button also subscribe see you in the next video
Info
Channel: Renaro Santos
Views: 7,088
Rating: undefined out of 5
Keywords: android unit testing, android testing, unit testing viewmodel, viewmodel
Id: UNLOX4U3CQA
Channel Id: undefined
Length: 11min 29sec (689 seconds)
Published: Sat Sep 10 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.