Testing in Android (MVP) – Part 3

In this last post of the three-part series on Testing in Android (MVP) we will go over how to add instrumentation tests that run on an Android device or emulator. If you have not checked out part 1 on unit tests or part 2 on integration tests, you should go back and check them out. Okay, let’s round off our series on testing in Android (MVP).

Setup your emulator for testing

In order to run instrumentation tests for our Android app we have to setup the emulator a bit differently than normal. When we run instrumented tests on an emulator of physical device we can’t wait for animations or network calls so we have to disable some animations.

Navigate to Settings | System | Developer options and disable all the animations.

If you haven’t enabled developer options, you can enable them by visiting Settings | System | About phone and tap the Build number until developer options are enabled. For additional reference visit the developer docs. Now that our emulator (or physical device) is all setup lets look at what dependencies we need to run instrumentation tests.

Dependencies in the app build.gradle file

Before moving forward we need to make sure to add the following testing dependencies to our build.gradle file to run tests with Espresso. Espresso is a UI testing framework for Android that allows us to find views and make assertions among many other things. For more information visit the link above but let’s focus on what dependencies we need to add.

Cool now let’s see what makes these tests useful.

Why Run Instrumentation tests?

Instrumentation tests will help us confirm our app shows data in a way that we expect based on our business logic. But wait… isn’t this what the integration tests do for our presenter? … Well yes, but instrumentation tests further confirm this since we can assert that a TextView contains some text, or that a Progress indicator is showing when data is loading.

Testing the View (Activity) from MVP

The first thing we need to do is create the test class. Let’s create a new Kotlin file and name it MainActivityInstrumentedTest.Kt. We need to add this into the androidTest folder of our project like so:

Next, let’s add a few annotations to the class. We need to tell the test runner we want to use the AndroidJUnit4 class so let’s add @RunWith(AndroidJUnit4::class) and then mark the test using @LargeTest annotation since we are running a large test. With all this setup we should have the following test class setup:

Finally, let’s create a rule for our test to launch the MainActivity by adding the following line:

Alright, we are all set up so let’s write our first test:

Perfect, you have written your first instrumentation test. Let’s press the run button next to the new method and see the green bar!

Nice work! Now let’s move on to the more difficult tests with the implementation of our custom keyboard.

Custom Keyboard instrumentation Example

Testing a custom keyboard is a non-trivial task so let’s see how we can do this. Well with any custom keyboard we need to use Espresso ViewMatchers to find our keyboard and then perform an action based on X and Y coordinates since we can’t find the views on the keyboard using their respective ids. So how does this look for our test?

Well, first let’s add a few helper functions for this to our test class. In the code snippet below we are adding a new method to click at an x and y coordinate within the view we have matched against (more on this in a bit). So here is what the code looks like:

It is important to note here the view we have, and the x and y position is relative to the View and not the entire screen. So we define the touch points in terms of the view we are matching against. Let’s look at the other helper method we need to add:

This method uses our keyboard default width percent and the row count to determine the coordinate x and y we want to press in the KeyboardView. Awesome so now let’s check out the test function to enter a price and hit the check button on the keyboard.

In the code above, we have called our getTargetXAndY() helper funtion and determined the point we want to single tap. From that target point we can interact with the other helper method clickXY passing in these target X and Y coordinates to hit the check button. Lets run the test and see that we can confirm we enter the price and then hit the check button.

Great job! We are finally done with our instrumentation testing for our tip calculator. The following is the end result with both the test method and the two helpers for full reference.

For additional content related to these keyboard tests check out my question and answer on StackOverflow.

Summary

Great job! You have just learned how to add instrumentation tests to your application and confirm the behavior of your application by using Espresso to assert that views on screen display the expected results when a tip is calculated. The full code for this tutorial is available on GitHub. This wraps up our 3 part testing series for MVP architecture within an android application.

If you enjoyed this tutorial please like, share or follow me on social. Don’t hesitate to leave a comment with any feedback!

 

Manageable Dialogs in Android

Why are dialogs so difficult?

Using Dialogs in Android has always been a bit of a pain. In our apps, we tend to have various kinds for different things resulting in tons of lines of code for such a simple purpose. When we need the user to know about something in our app or that an error occurred we show an AlertDialog. For business decisions it may require that a network request needs to block the user from doing anything but wait, so we show a ProgressDialog (now deprecated). Additionally, if we need to request permission for something dangerous (i.e. versionCodes >= 21) we do that. And then in more complex cases we ask the user something and have them perform an action by pressing one of three buttons (positive, neutral, negative), provide a list of options either single choice or multiple, or even collect input from the user. As you could imagine (or may have experienced before) this can lead to tons of the same code doing slightly different things littered throughout your codebase.

This can become a real problem when we need to update certain aspects of the dialogs within our application such as the theme or maybe we were previously using cancelable dialogs and now we want them to not be cancellable. This could become a large task consuming valuable time! As creative engineers and proponents of object-oriented programming, however, we have managed to get around this by introducing our own version of boilerplate to solve these problems using static methods within a utility class. This can make these changes much easier and provide a reusable set of methods for other projects.

For example, the following DialogUtil.java class has multiple ways of showing dialogs in java using this pattern:

So great! Now we have a utility class we can leverage for any project in which we need to display dialogs. It is easy to make any changes in this utility class if we need to update our apps dialogs preventing us from having to open various files to update each dialog one by one. Although this isn’t perfect it is much better than the alternative. Using this utility class we can show a dialog like so:

The alternative without that wrapper class shows why it is more preferable to wrap the methods:

Could you imagine searching for this code in your project and changing R.style.AppTheme_Dialog to something else for every instance (of course we could use find & replace with modern IDEs…), rather than opening the utility class and updating a single place?! (I can’t!) However, we choose to wrap the functionality using Java doesn’t matter too much because, with the introduction of Kotlin, we now have a better way to incorporate dialogs into our codebase with much less boilerplate.

A better approach with Kotlin

The Kotlin programming language treats functions as first-class citizens. From the Kotlin docs:

Kotlin functions are first-class, which means that they can be stored in variables and data structures, passed as arguments to and returned from other higher-order functions. You can operate with functions in any way that is possible for other non-function values.

But what does this mean for Dialogs?

Well, instead of including listeners within our activities or directly in our DialogUtils class (see above) we can just pass a function as a parameter to one of our utility functions in Kotlin making our code even more readable.

With a custom extension function on the Context class, we can create the same Dialog with a list and a single choice option style using the sample from Util.kt :

and then its usage from MainActivity.kt:

The best part is we can now use any class that inherits from Context and this displaySingleChoiceDialog method is available to us!

Or if you like the popular library Anko you can do the same thing:

Don’t forget to add the following dependencies to your build.gradle file if you like Anko better:

Summary

Working with dialogs in Kotlin is much easier than doing the same in java. Since functions in Kotlin are first class we can move all the boilerplate for our dialogs into a common utility file and then use lambdas to handle the actions performed on the dialogs within our activities.

NOTE: with Kotlin’s null safety we could extend a single function in a utility file to handle the building of any dialog we want!

If you enjoyed this article or have a comment about an error please leave a comment.

Also, don’t be a stranger and follow me on social media!

Adding PopupMenu to an adapter item

In Android, lists tend to have actions associated with them. We can do this via onClick(View v) or event the outdated long press action, but what if we want to give an item in our list a menu style drop-down? Well, this is actually pretty easy to do with the PopupMenu class from Android. So how do we use it?

Since I have received a lot of traffic on my StackOverflow post about just this thing, I have decided to share a quick tutorial on how to add them to your adapter.

Piggybacking off the same repository from our ViewModel and LiveData demo we can easily add a drop-down menu via the PopupMenu class.

First, let’s add the following strings to our strings.xml file:

Then let’s create a menu using these values as our titles:

Next, let’s add a new overflow image button using vector assets:

We are almost done, now we just need to add an AppCompatImageButton to our layout:

Now let’s hook it all up to our adapter code in our onBindView(holder: ViewHolder, position: Int) method!

And there you have it! Your list items will now have a PopupMenu where you can react to the list items overflow button.

Please leave a comment or share if you enjoyed the tutorial.

The full source code is available on Github.