Android Testing (Kotlin) — Unit tests

Adalberto Plaza
8 min readOct 23, 2018

--

In this series of posts we are going to talk about Android Testing. It’s a big field to talk about, but here there are some important points and tips.

  1. Introduction.
  2. How to test.
  3. Unit tests.
  4. Integration tests.

We are going to do some examples to easily understand how typical unit tests are done in Android. So, in addition to read this post, I encourage you to try the examples by yourself.

Basic Unit Test example

The following class can be used to save a number in a persistent storage. It has a public method, which receives a number. If the number is valid, it’s saved on the “database” using a DAO. The dao can throw an exception, so it’s thrown in the saver method as well. Note: we don’t need a real PhoneNumberDao class, because we are testing the saver helper and not the dao. So, the database saving is just a supposition.

I invite you to try to solve the following points by yourself before checking the answers.

Test the use of saveContact(contact):

  1. Empty contact “”, should returns false.
  2. “Roy” contact should return false.
  3. “Jen and Douglas” contact should return false.
  4. “Maurice” contact should return true.
  5. “Maurice” contact should return false when the dao can not create the number.
  6. “Maurice” contact should return false when the dao throws an exception.

Done? Let’s see the solution!

Full text green output

Before the explanation, remember that you can (should) organize the tests like they were a regular class. You can re-use methods, refactor the code and so on.

Notice how I have created an inner class with the name of the method I’m about to test. If we have multiple methods and we need to do different test per method, creating a new inner class per each function is a good way to have our tests organized.

Starting from the end of the test class, you can see three methods to create the ContactSaver object, depending on the behavior we expect from the external ContactDao it uses. If we want to create a successful one, a failing one or even one which raises an exception when it’s invoqued. We can do this on many other ways, but in this example we have extracted the creation into these simple “given” methods.

And last but not least, let’s see the tests. As you can see, all of them have the given-when-then structure.

  • Test with empty contact: instantiates a successful ContactSaver and pass to create method an empty string, expecting it to return false.
  • Test with short or long names: it instantiates a success ContactSaver and calls the create method with short and long names respectively. Since they should not be accepted it expects a false result.
  • Test with valid contact: it instantiates a success ContactSaver and calls the create method with valid name. Everything should be ok, so it expects true.
  • Test with a failing dao: it instantiates a ContactSaver with the dao returning false. It uses a valid contact but expects a false result since the day is prepared to fail.
  • Test with with an exception in tha dao: it instantiates a ContactSaver with the dao throwing ContactDaoException. Because of that, the saver should return a false return.

View Presenter Unit Test example

Now that we have seen a very basic unit test, let’s do it something more Android related. Probably you are familiar with Model-View-Presenter, so in this case we are going to test the presenter with unit testing. For this purpose is very important to keep the presenter free of any Android subsystem call. This is not always possible, but it’s a good practice, because we can test our presenter in a really quicker and easier ways than having Android references. Android references implies that we need an emulator to run with, and we would need to mock much more objects as well.

Let’s say we have the ContactActivityPresenterand its view interface. The presenter is used to be the communicator between the view and the ContactSaver.

(Note: using literal strings is not a good practice in Android, you should use strings.xml. I do it that ways because of simplicity)

Again, I invite you to try the following points by yourself before checking the answers. Remember that we are going to test the presenter and not the ContactSaver, which is covered by the previous tests We do not need any activity for the view as long as we can mock it. Tip: use test doubles to check the presenter callbacks

  1. When save a valid contact, the view is notified with the positive result.
  2. When save a non-valid contact, the view is notified with the error.
  3. When the view is not attached, there’s no crash if we try to use the presenter method.

Done? Let’s go with the solution!

Again, we start (at the bottom of the class) setting up the given methods. In this case we want to get different variants of the presenter depending on the mocked ContactSaver inside it. One of them returns true when we try to save a contact, and the other one just returns false.

These tests are pretty simple. Basically we get the necessary object in the given block and attach the view if necessary. Notice that now we are not expecting any result but we are expecting a call to the view. That check is done in the then block using Kluent and spying the callbacks. The syntax is pretty simple in the same way specifying the behavior of the mocked object was. Notice the new setUp( function. In it, we are resetting the view in order to clean it calls counter between tests. Otherwise, it can confuse the calls from previous tests in the current one.

  • Test saving the contact should call the success function of the view.
  • Test not saving the number (because it failed) should call the error function of the view.
  • Test with non-attached view should not do anything (this implies do not crash as well)

Bonus1: testing background thread executors

If you are familiar with Android programming, you probably are aware about thread handling in one of the daily basis in the environment. This is because we want to keep heavy tasks out of the UI thread. So probably, in addition to the presenter, you would have some background runner, executor or similar.

Let’s add a basic thread executor to our project. The task we are running is actually a dummy task, so we will just add a small delay to simulate de spent time in the background thread.

Now, we can use it in ContactActivityPresenter. Let's change the onSaveContact function to run the task with the BackgroundExecutor. Note: we are not redirecting the response to the UI thread to simplify the example.

fun onSaveContact(name: String) {
backgroundExecutor.execute {
val saved = contactSaver.saveContact(name)
if (saved) {
view?.showContactSaved()
} else {
view?.showContactSavingError("Error saving the contact")
}
}
}

Now, try to run the tests again. What happens? Are the test “in green”?

Probably not, they fail since you introduced the background thread handling. This is happening because of a simple reason: test are being run in the main thread without waiting for any other thread to finish. As soon as the main thread finishes to run the assigned code, the test runner executes the asserts. But the results/callbacks in the new thread handler are not finished yet. Although the test are correctly written they are failing because of the parallel execution of the thread. How can we fix this?

There’s an easy way. It’s actually the same way we solve most of the test issues: mocking the BackgroundExecutor. If we mock it, we can override the execute method and run the received task in the same thread instead of creating a new one. This way, we keep the thread handling in the app, but we test it in a single thread in our tests. (This is applicable to executors, handler, async tasks and so on).

This is how the mocked object looks inside the test class (we are doing it manually this time instead of using Mockito).

Now, all the test should pass correctly.

Bonus2: static helpers

Static helpers are very common in some scenarios (in spite of not beeing a good practice). But they are a big problem for testing. I mean, we can test them with no problem: we just need to call their methods and check they return the expected result. But what if we want to mock them? what if the BackgroundExecutor was a static object? We could not test our presenter just because of the executor can not be extender now to create a mocked object. Too bad..

Best solution is to avoid static classes and use Dependency Injection (like we have done in the example). That way we will get the same helpers everywhere, and we can mock it in the tests. However, this is not possible in some established projects which are already using static helpers (and we can not change them, at least in short time).

There are two alternative “solutions” in order to make static helpers compatible with tests:

  1. Keep the static helper, don’t mock it and trust it. This is risky because we can not simulate the different helper responses inside the class which is using it. Moreover, this solution won’t work for helpers which need to be mocked to make the test pass, like BackgroundExecutor.
  2. Make the test singleton with an injectable Instance and getInstance() method. In this case we need to change all calls to the helper to use the instance, and inject a mocked one in the tests. This will fix the problem with mocking the helper in tests and its use.
  3. Wrap the static helper with an instantiable class. This is so tedious, because we need to wrap every call and change it everywhere. But could be useful whe the static helper is shared by different projects or modules (we cannot change it), but we don’t want it to be static in our project or module.

Note how important is adapt the base code to tests in order to be able to run them. In other words make the code testable.

Originally published at https://adalpari.github.io on October 23, 2018.

--

--