How to test Android Apps: Unit Testing

Now we dive into unit testing.

The goal is to test a specific part of your code, just a particular class or method. That way, we can find sooner where bugs appear in your application. For that, we need to test that code in isolation, mocking all its dependencies with fake ones we can control.

The most popular library to achieve that is Mockito.

Example

Let's test this class:

class Controller {

    private final Database database;
    private final Screen screen;

    public Controller(Database database, Screen screen) {
        this.database = database;
        this.screen = screen;
    }

    public void check() {
        List<String> fruits = database.getFruits();

        if (!fruits.isEmpty()) {
            screen.showFruits(fruits);
        } else {
            screen.showEmptyMessage();
        }
    }
}

Like we explained before, all dependencies are provided in the construtor, to they can easily be changed in testing.

Here's how we can test the check() method:

public class ControllerTest extends AndroidTestCase {

    private Controller controller;
    private Database database;
    private Screen screen;

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        database = mock(Database.class);
        screen = mock(Screen.class);
        controller = new Controller(database, screen);
    }

    public void testCheckWithFruit() {
        List<String> fruits = new ArrayList<>();
        fruits.add("banana");
        fruits.add("apple");
        when(database.getFruits()).thenReturn(fruits);

        controller.check();

        verify(screen).showFruits(eq(fruits));
    }

    public void testCheckEmpty() {
        List<String> emptyFruits = new ArrayList<>();
        when(database.getFruits()).thenReturn(emptyFruits);

        controller.check();

        verify(screen).showEmptyMessage();
    }
}

Since we mocked the Databaseand Screen instances, all methods we call from them will be ignored and return null. If we want then to return a specific value or object, we need to stub them with when(...).thenReturn(...).

In this example, we stub database.getFruits() to return our own list of fruits. If there's a bug inside the getFruits()method, we don't want this test to crash, because we're only testing the Controller.

Then, we test if the right methods of the Screeninstance are called. We can even check if they were called with the arguments we wanted.

Note: value objects, like String, List or database objects are not mocked.

Avoiding Android dependencies

Most Android objects don't allow access to their constructors and dependencies. How can we test them? Directly, you can't, not with unit testing, in isolation.

But there are tricks to work around some of the issues: - Use an architecture like MVP to move your most important code to plain java classes, like Presenters - Add setters just for testing (use the @VisibleForTesting annotation) to switch dependencies to a mocked version - Use a mocked version of Android with Roboelectric (advanced)

More resources


How to test Android Apps

  1. Introduction
  2. Architecture
  3. Unit Testing
  4. Instrumentation Testing
  5. Other details