Join Chiu-Ki Chan for an in-depth discussion in this video Testing with MVP: ArgumentCaptor, part of Effective Android Testing for Mobile Developers.
- [Instructor] Finally, we will test loading a actual recipe. Create a new test method called Load Water and Favorite. Again, we will use the @Test annotation. Then, public void, load water and favorite. What we are going to here is to load water.TXT out of the resources folder here. This is the same as what we did when we wrote recipe test.
So, let's go back to that file. Press Command O and search recipeTest. Scroll up to look for the water function, copy lines 12 and 13. Then, we can press Command E to go look at the recent files to switch back to RecipePresenterTest.java. Here, inside the Load Water and Favorite function, in line 41, paste in what we copied.
What we are doing here is that we try to load the recipe out of the file. For consistency, I will replace the word RecipeTest with RecipePresenterTest so that we stay within the same class. Now that we have a recipe, we can return it whenever store.getrecipe gets called. We can copy that from the function Recipe Not Found. Copy line 32, and paste it after line 45.
But, instead of having it return null, we will return the recipe. Next, call presenter.loadrecipe with the ID Water. Presenter.loadrecipe, and give it the string Water. Let's run the test. Great, it passes. We have verified that when we call LoadRecipe on the presenter with the string Water, it does not crash. Let's do a bit more.
As indicated by the method name I gave it, we also want to verify the behavior when we try to favorite this recipe. What we are going to do is we are going to call Toggle Favorites. So, after we load the recipe, we will call Presenter.toggleFavorite. When we start this test, the recipe should not be favorited already. This is because favorites is a stop. You can scroll up to the method, set up, to verify that.
You can see that Favorites is set up as a Mockito stop The behavior of Mockito stops is that it will return false whenever the function signature returns a Boolean. If you take a look at recipe presenter, when the recipe is loaded and is not null, in line 29, we will be calling favorite.get, which returns a Boolean, and like I said, it will be false. So, setFavorite is going to be false. Go back to the test, scroll down.
In line 49, we are trying to toggle favorite. The initial state is false, meaning that when favorites toggle got called, it should return true, flipping from the default false. Let's stop that out. Point your cursor at line 46, press command D to duplicate. We are going to call favorites, so replace store with favorites, and replace the function getRecipe with toggle.
The return value, as I said, should be true. Once again, this is the assign phase of assign at assert. When presenter toggle favorites is called, it calls through to favorites.toggle, and we want it to return true, so that we'll flip this from not a favorite to a favorite. Next, we are going to verify the UI. How do we verify the UI? We are inside just pure Java.
What we want to do is, to verify that, the presenter calls set favorite on the view with the correct variable. To do that, we will need an argument captor. Argument captor, after type Boolean, we will call it captor. Initialize it by calling argumentCaptor.forClass, and then give it the Boolean class. Next, we will call verify.
Mockito.verify, and then view, coma, Mockito.times 2. We are saying that we want to verify that the set favorite function is called twice. First, set favorite is called when we load the recipe, and a second time, it is called when we toggle favorite to update a UI. So here, we will do .setFavorite, and then we are going to use the argument captor to capture the value that is passed to the set favorite function.
Captor.capture. What this line does is that we want to verify that the view set favorite function is called twice, and then, the values that we call it with is stored inside the captor. Next, we are going to verify the values captured by the captor. AssertFalse, and then captor.getAllValues.get 0.
What we are doing is asking the captor to give us all the values it has captured, and verified that the first entry is false. We want it to be false, because initially, when we call set favorite is when the time we load the recipe. We started off as a not favorite recipe, so it should be false. Next, command D to duplicate this line, and change it from assertFalse to assertTrue, and also, from get 0 to get 1.
This means that, for the second value that's captured by the captor, we want it to be true, because this happens after toggle favorite is called, and then the presenter would call set favorite with true to update the UI. Let's run the test. Click on the green triangle on the gutter, and choose run. Yay, that passed. Wow, that was a lot. In the next video, let's walk through everything we did.
- Why test?
- Local vs. on-device
- Code coverage
- UI testing
- Hermetic environment
- Dependency injection
- Testing with MVP