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!

 

Testing in Android (MVP) – Part 2

Integration Testing

Integration tests are important in Android so we can ensure the behavior of the integration between the view and the model work correctly. So how exactly do we write these integration tests since the presenter relies on 2 other objects the View & Model?

In the previous post, we added a new dependency to our project called MockK. What is MockK? Well, MockK is a mocking framework for Kotlin. A mocking framework allows us to verify the behavior of an object without having to build the objects from scratch among various other things.  More information about MockK can be found at the website.

So now we know about mocking frameworks let’s see how we use them to build out integration tests.

For brevity, I am only going to show how we use the mocking framework to write the integration tests although you can find the source code for the MainPresenter at the github page.

Annotations

Alright, so what have we done here?

With the property fields, you will notice some annotations, @RelaxedMockK, @MockK. These annotations provide use with mocked version of the classes they sit above. For example, @RelaxedMockK on the Contract.View class is setting up a mock object that is relaxed in nature.

From the docs:

Relaxed mock is the mock that returns some simple value for all functions. This allows to skip specifying behavior for each case, while still allow to stub things you need. For reference types chained mocks are returned.

Source

The @MockK annotation creates the standard version of the mocked object. This means we want to mock the class but will provide the behavior of the class when interacted with, however, we are passing it a parameter relaxUnitFun which tells the framework to allow functions returning Unit to be relaxed. In our case, this affects the setTipOption function which has no return value or Unit if you prefer to be explicit.

from the docs:

In case you would like Unit returning functions to be relaxed. You can use relaxUnitFun = true as an argument to mockk function, @MockKannotation or MockKAnntations.init function.

Source

Although we only use these annotations, MockK provides many other useful annotations that are worth looking into.

The Setup

Okay, so now that we have understood a bit about the annotations we are using let’s turn our attention to the setup method:

Here we, initialize the mocks and set up the model to return the values we want to use when interacting with the mock. Additionally, we tell MockK to init the annotated classes from above. Since this method is annotated with @Before it will run before every test is executed.

The Tests

These two tests that we set up above allow us to ensure the behavior of the start method in our presenter as well as the changeTipPercent method. We then use the verify lambda from MockK to assure the view has been interacted with in an expected way. That’s it! You now know how to use MockK to write a simple integration test. What happens though when we want to adjust the behavior of a mock after setup occurs?

Changing behavior with every

Each of the above methods has a line:

This line is altering the behavior of the computeTotalPrice function of our model so we can verify the other methods of the view are interacted with in an expected way. We can now verify that the displayFinalPriceWithTip function of the view is called as well as the displayError method when we pass in a bad value.

Summary

Wow, look at you go! You now know how to create an integration test for your presenter in the MVP architecture using MockK. In the last part of this testing series with the MVP architecture we will take a look at the instrumentation tests on Android for running tests on an Emulator or physical device. See you then!

If you enjoyed this post please leave a comment, like or share, and follow me on social media.

Testing in Android (MVP) – Part 1

In this first post of a three-part series, we will walk through unit testing an android application that uses the MVP architectural pattern. By the end of the three-part series, we will have discussed unit testing, integration testing, and instrumentation testing. The first two will allow us to run tests very quickly on our local development machine. For the third, we will need to set up an emulator or use a physical device to run the tests. This series will both show you the benefits of having chosen the MVP pattern as well as the various libraries and frameworks that help us write tests against this architecture.

Jumping Right In

Picking back up with the MVPDemo from the previous post, where we built a Tip Calculator app, we are now going to test our code.

Test our code? But that’s a waste of time, we have to ship!

With automating our unit tests we can provide:

  1. scale
  2. insurance
  3. peace of mind

In other words, with automated unit tests, we can ensure the code that we wrote last week does the same thing this week, even if someone else has committed a new feature.

The two-thirds Rule

In Android, we should test at least 2 out of the 3 things from the list below to ensure that our app’s core functionality works:

  • Unit tests – the smallest possible test we can write which asserts an actual value matches an expected value.
  • Integration tests – tests that ensure the proper integration of 2 or more components. (think presenter in the MVP pattern)
  • Instrumentation tests – tests that run on a physical or emulated device. These are not fast tests but they can be useful in a CI system or if you want to make sure things display as expected (asserting views are on screen or contain certain text, clicking this button performs this action, etc.).

Okay so now that we know the types of tests we should be writing let’s ask the real question…

Is there really a two-thirds rule?

Well, no. The point is you should consider covering the majority of your code with some tests. Being able to confidently know that two-thirds of the behavior of the code you have just written is guaranteed will drastically improve your process as an engineer and team member.

In my previous post, discussing the MVP architectural pattern, we can see how the decoupling of our code allows us to more easily test the functionality within our app. Specifically, we can see how the three test types we just mentioned apply to the MVP pattern.

As you can see, we can test the model with fast unit tests using either JUnit , AssertJ or Robolectric. We can test our presenter using a combination of AssertJ & MockK (Mockito if you prefer it too MockK). And finally, we can test our view code using the Espresso library or UIAutomator . These are just a subset of the popular testing frameworks available to us now but let’s get to the unit testing for this first part.

Setup

Before we get started we have some setup to take care of to import the correct dependencies for testing. In the top-level build.gradle file, add the following line (e.g denoted by the // 1):

and in your app level build.gradle file add the lines (e.g denoted by // 1, // 2 // 3):

  1. Adds the plugin for JUnit 5 to work with Android
  2. Adds the test/kotlin directory to our test source sets
  3. Adds the JUnit 5, AssertJ and MockK testing dependencies

Writing a Unit Test

One of the most important areas to test within our code base is our app’s model code. No, I am not talking about testing a POJO or POKO (Kotlin variant), I am talking about the Model used to manage the data within our application! The code that determines the actual behavior of the functionality provided for a view. We have to test this code to guarantee our app works as expected. But what does this look like?

MainModel code (for reference):

Looking at our model code we see it provides the following functionality for use:

  • MainModel() (default constructor)
  • setTipOption(position: Int) : Unit (sets the tip option and returns nothing)
  • computeTotalPrice(price: String?): Double (computes the price returns total)

Since we don’t have any constructor arguments lets start by assuring the setTipOption code works as expected. We want to assert that with a valid index, the tipOption is set to the expected value.

Okay, so what did we just do? Well, we set the tip option to 0 (the first index of the array in our model) which sets our tip to 5% so when we compute the total price of $100 check, we should expect that we get back a value of $105.0 for 5% of $100 = $5.

We have written our first passing test but if we run the same test with code coverage we will notice that we haven’t tested the full source code for this method. So, let’s take a look at one other test case: the invalid tip option. If you look back up at the MainModel code, we can see that if the index of the argument is out of range of valid tip options we default to a 20% tip. We will want to make sure that code works too!

Okay perfect all code within the setTipOption method is now covered and the behavior works as expected. Going forward, if any of the code in this method changes we now have a couple of tests to make sure we don’t break the expected behavior. If we do break the expected behavior (assuming a new feature or new default is chosen by the product team…), we will update the test case and move on. Additionally, we want to test out the functionality of the computeTotalPrice method.

Since this method is a bit more complicated we have to test it with at least 3 tests:

  1. Test that a good price will yield the expected result
  2. Test null or empty price yields 0.00 return value
  3. Test if we have a negative price that all values will be 0.00

Well done! 100% test coverage for a single class and the best part is in under 1 second we can now test that the MainModel code works as expected. As an exercise, write some tests to exhaust the tip calculator options testing the remaining percentages return the expected values.

All of the source code can be found on GitHub.

Summary

Great job! Now you know how to write unit tests that guarantee the behavior of your tip calculator’s model code. In this post, you have learned that there are 3 types of tests you should consider when it comes to Android application development. You have learned about some of the frameworks used in the testing process. And you have written your own unit tests.  In my next post, I will show you how to test the presenter code in the MVP pattern to guarantee the integration between the View and Model.

If you enjoyed this post please share or comment! And feel free connect with me on social media.