Android: Unit Testing Apps with Couchbase, Robolectric and Dagger


This Android / Gradle project on GitHub shows how to integrate Couchbase, Robolectric and Dagger so that unit testing can occur without the need for a connected device or emulator.

Background

I need a database for my TripComputer app so that users can keep a log of their Journeys. I could use SQL Lite, but I prefer not to use SQL if possible. With SQL you’re forced to maintain a fixed schema and SQL Lite doesn’t offer any out of the box cloud replication capabilities, unlike most NoSQL databases.

Couchbase Lite for Android is an exciting new embedded NoSQL database, but because its ‘Database’ and ‘Manager’ classes are Final and require native code, it’s not trivial to mock them or integrate them into apps that utilise the popular Robolectric testing framework.

Therefore, in order to support off-device Java VM based testing with Robolectric it is necessary to write custom interfaces and use a dependency injection framework that will allow the injection of mock objects to occur when testing. To achieve this ‘dependency injection’ of mocks, I’ve used Mockito and introduced the Dagger framework into the code.

Software Versions

  1. Couchbase-lite 1.0.3.1
  2. Robolectric 2.4
  3. Dagger 1.2.2
  4. Mockito 1.10.19
  5. Android Studio 1.1 Beta 3 (optional)

About The Sample App

The App I’ve built here is very simple. When the user clicks the Save button on the screen, in the background a new document (technically a `java.util.Map`) is created and saved to the embedded Couchbase NoSQL database. While saving the new document, Couchbase automatically assigns it an ID and it is this ID that is ultimately displayed to the user on the screen after they’ve clicked the Save button. The document id’s in Couchbase take the form of GUID’s.

The App Code

Roughly speaking, in the `app` codebase you’ll see the following…

1. `MyActivity.java` is a simple Android action bar activity that extends a `BaseActivity` and requires a `PersistanceManager` to be injected at runtime so it can talk to the database.

2. `PersisitanceManager.java` is a class that acts as a DAO object to `MyActivity`, managing the persistence of ‘Map’ objects. It offers only INSERT and GET operations in this sample and requires a `PersistanceAdapter` implementation to be injected into it.

3. `PersistanceAdapter.java` is an interface that defines INSERT and GET operations on `Map` objects. This interface is required later when mocking & testing.

4. `CouchbasePersistanceAdapter.java` is a concrete implementation of the `PersistanceAdapter` interface. It utilises Couchbase and depends on a couchbase `Database` object which must be constructed by Dagger and injected into it.

5. The injectable objects that require non-trivial instantiation (like the Couchbase `Database` object for example) are defined by `@Provides` methods in a Dagger `@Module` in the `MyActivityModule` class.

At runtime, Dagger, `MyActivity`, `BaseActivity` and the `App` application classes take care of constructing an `ObjectGraph` for the application and inserting the required dependencies so that all the various `@Inject` requirements can be met. The “Instrumentation (integration) Tests” in the Android App gradle project test that this integration and dependency injection is working as expected.

The Robolectric Tests

Because it’s also desirable to perform testing without a device or emulator, there’s a set of Robolectric tests for the App’s `MyActivity` class that test the same ‘Save’ feature but without the need for a connected or emulated device and without the need for an embedded Couchbase database.

In the `app-test` gradle project you’ll see the following…

1. `MyTestActivity.java` extends the MyActivity class and `@Overrides` the `getModules()` method. This method constructs and returns a `TestMyActivityModule` instance. `TestMyActivityModule` is an inner class which defines an alternative (overriding) Dagger `@Module` that can also provide a `PersistanceManager` for injection into the `MyTestActivity` when testing. This module `@Provides` a fake, programmable `PersistenceManager` _mock_, not a real persistance manager as is expected under normal conditions.

2. `MyActivityRobolectricTest.java` is a standard Robolectric test, but it’s Robolectric controller builds a new `MyTestActivity`. The method `testClickingSaveButtonSavesMapAndDisplaysId()` tests that clicking the _Save_ button has the required affect by pre-programming the `PersistenceManager` mock with behaviours and then verifying that this mock has indeed been called by the Activity as expected.

Running the Sample

To run the tests for yourself just clone or download this repository and then execute the following gradle commands. For completeness, I’ve included some Android Instrumentation Tests as well and you can run them with `gradlew connectedCheck` (assuming an emulator or device is present).

gradlew clean
gradlew assemble
gradlew check
gradlew connectedCheck (this is optional and assumes a device is present)

Acknowledgements

Many thanks to Andy Dennie for his Dagger examples on GitHub. These were really helpful to this Dagger noob when trying to understand how to integrate Dagger with Android.

About the Author

Ben Wilcock is the developer of TripComputer, the only distance tracking app for Android with a battery-saving LOW POWER mode. It’s perfect for cyclists, runners, walkers, hand-gliders, pilots and drivers. It’s free! Download it from the Google Play Store now:- Get the App on Google Play

You can connect with Ben via his Blog, Website, Twitter or LinkedIn.

Working with Robolectric and Robotium in Android Studio and Gradle


I develop the TripComputer App for Android but I find testing apps using the standard Android Instrumentation framework is really slow and painful. Slow testing cycles can kill productivity and are a well documented disincentive to TDD. Therefore, most Android tutorials that talk about testing bestow the virtues of switching to something like the Robolectric framework when unit testing Android apps.

Robolectric is great because it allows you to test your App against a ‘simulated’ set of Android SDK API’s using your desktop’s java virtual machine (jvm) as opposed to either ’emulating’ these API’s in a pretend device or accessing them on a physical device which is what the standard Android Instrumentation Testing framework does.

Robolectric also allows the use of JUnit v4 style testing annotations rather than the older JUnit v3 style required by the built in Android Instrumentation testing framework.

However, there’s a problem: getting Robolectric to work in Android Studio is difficult.

I’ve been an Android Studio user ever since it first went public nearly 2 years ago. It’s an awesome IDE but one consequence of it’s use is that it promotes the Gradle build system to be the default choice for Android projects. This is good news for Android developers but unfortunately, getting Android Studio, Gradle, Robolectric, Robotium, AppCompat and JUnit to all work happily side by side is a real pain in the rear.

Over the past year or so it’s been a slowly improving picture, but now Android Studio has gone to a 1.0 release, I (and many others) have figured the time was right to try and bring these tools together.

The android-alltest-gradle-sample project on GitHub is my attempt to create a template project that can be used as a starting point for anyone who wishes to use these best of breed Android Testing tools together with Gradle and Android Studio in one project.

The tools integrated and supported by the sample project so far are:-

  1. AssertJ for Android. Makes the testing of android components simpler by introducing an android specific DSL for unit testing.
  2. Robolectric. Allows the the simulated testing of Android apps (i.e. device API’s are simulated, so there is no need for an emulator or physical device).
  3. JUnit. Used to simplify testing of core Java and simulated Android tests.
  4. Android AppCompat v7. Popular support library developed by Google to improve support for backwards compatibility in Android.
  5. Robotium. Used to augment normal Instrumentation Tests and provide black box integration testing from Android.

There are lots of blogs out there talking about doing a similar thing, but as far as I know, this sample project is the first to demonstrate the combined use of these tools without the need for any special Gradle or Android Studio plugins to be applied.

Instrumentation Tests do still have an important role to play. They are great when used to test how well ‘integrated’ the individual units of code are when combined together to form an App. I find that thinking of instrumentation testing as ‘Integration Testing’ allows me to appreciate it’s true benefit more. As a bonus, the sample project also includes Robotium, to make integration testing simpler and more productive.

To use the sample project & code, simply clone the repository (or download a ZIP). Import the project (as a Gradle project) into Android Studio, test it and then start running code. Check out the Acknowledgements section in the readme for further help, tips and advice (including how to execute your Robolectric tests from within Android Studio in addition to the cmdline).

For more information, check out the project on GitHub.

About the Author

Ben Wilcock is the developer of Trip Computer, the only distance tracking app for Android with a battery-saving LOW POWER mode. It’s perfect for cyclists, runners, walkers, hand-gliders, pilots and drivers. It’s free! Download it from the Google Play Store now:-

Get Trip Computer on Google Play

Event Tracking with Analytics API v4 for Android


As I’ve learned from developing my own mileage tracking app for cyclists and commuters, getting ratings and feedback from users can be challenging and time consuming. Event tracking can help by enabling you to develop a sense of how popular a particular feature is and how often it’s getting used by users of your app.

In Android, Google Play Services’ Analytics API v4 can be used to gather statistics on the user-events that occur within your app.  In this post I’ll quickly show you how to use this API to accomplish simple event tracking.

Getting started.

It’s important to say at this point that all of these statistics are totally anonymous. App developers who use analytics have no idea who is using each feature or generating each event, only that an event occurred.

Assuming you’ve set up Google Analytics v4 in your app as per my last post, tracking app events is fairly simple. The first thing you need is your analytics application Tracker (obtained in my case by calling getApplication() as per the previous post). Bear in mind that this method is only available in an object that extends Android’s Activity or Service class so you can’t use it everywhere without some messing about.

Once you have your application Tracker you should use an analytics EventBuilder to build() an event and use the send() method on the Tracker to send it to Google. Building an event is easy. You simply create a new HitBuilders.EventBuilder, setting a ‘category’ and an ‘action’ for your new event.

Sample code.

The sample code below shows how I track the users manual use use of the ‘START’ button in Trip Computer. I have similar tracking events for STOP and also for the use of key settings and features like the activation of the app’s unique ‘battery-saver’ mode (which I understand is quite popular with cyclists).

// Get an Analytics Event tracker.
Tracker myTracker = ((TripComputerApplication) getApplication())
.getTracker(TripComputerApplication.TrackerName.APP_TRACKER);

// Build and Send the Analytics Event.
myTracker.send(new HitBuilders.EventBuilder()
.setCategory("Journey Events")
.setAction("Pressed Start Button")
.build());

Once the events are reported back to Google, the Analytics console will display them in the ‘Behaviour > Events > Overview’ panel and display a simple count how many times each event was raised within the tracking period. You can also further subdivide the actions by setting a ‘label’ or by providing a ‘value’ (but neither of these is actually required).

More information.

For more information see the following articles:-

https://support.google.com/analytics/answer/1033068?hl=en
https://developers.google.com/analytics/devguides/collection/gajs/eventTrackerGuide#Anatomy

About the Author

Ben Wilcock is the developer of Trip Computer, the only distance tracking app for Android with a battery-saving LOW POWER mode. It’s perfect for cyclists, runners, walkers, hand-gliders, pilots and drivers. It’s free! Download it from the Google Play Store now:-

Get Trip Computer on Google Play

Working with Google Analytics API v4 for Android


For v4 of the Google Analytics API for Android, Google has moved the implementation into Google Play Services. As part of the move the EasyTracker class has been removed, but it still possible to get a fairly simple ‘automatic’ Tracker up and running with little effort. In this post I’ll show you how.

Assumptions:
  • You’re already using the Google Analytics v3 API EasyTracker class and just want to do a basic migration to v4 – or –
  • You just want to set up a basic analytics Tracker that sends a Hit when the user starts an activity
  • You already have the latest Google Play Services up and running in your Android app

Let’s get started.

Because you already have the Google Play Services library in your build, all the necessary helper classes will already be available to your code (if not see here). In the v4 Google Analytics API has a number of helper classes and configuration options which can make getting up and running fairly straight forwards, but I found the documentation to be a little unclear, so here’s what to do…

Step 1.

Create the following global_tracker.xml config file and add it to your android application’s res/xml folder. This will be used by GoogleAnalytics class as it’s basic global config. You’ll need to customise screen names for your app. Note that there is no ‘Tracking ID’ in this file – that comes later. Of note here is the ga_dryRun element which is used to switch on or off the sending of tracking reports to Google Analytics. You can use this setting in debug to prevent live and debug data getting mixed up.

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="TypographyDashes">

<!-- the Local LogLevel for Analytics -->
<string name="ga_logLevel">verbose</string>

<!-- how often the dispatcher should fire -->
<integer name="ga_dispatchPeriod">30</integer>

<!-- Treat events as test events and don't send to google -->
<bool name="ga_dryRun">false</bool>

<!-- The screen names that will appear in reports -->
<string name="com.mycompany.MyActivity">My Activity</string>
</resources>

Step 2.

Now add a second file, “app_tracker.xml” to the same folder location (res/xml). There are a few things of note in this file. You should change the ga_trackingId to the Google Analytics Tracking Id for your app (you get this from the analytics console). Setting ga_autoActivityTracking to ‘true’ is important for this tutorial – this makes setting-up and sending tracking hits from your code much simpler. Finally, be sure to customise your screen names, add one for each activity where you’ll be adding tracking code.


Step 3.

Last in terms of config, modify your AndroidManifest.xml by adding the following line within the ‘application’ element. This configures the GoogleAnalytics class (a singleton whick controls the creation of Tracker instances) with the basic configuration in the res/xml/global_tracker.xml file.


<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="TypographyDashes">

<!-- The apps Analytics Tracking Id -->
<string name="ga_trackingId">UX-XXXXXXXX-X</string>

<!-- Percentage of events to include in reports -->
<string name="ga_sampleFrequency">100.0</string>

<!-- Enable automatic Activity measurement -->
<bool name="ga_autoActivityTracking">true</bool>

<!-- catch and report uncaught exceptions from the app -->
<bool name="ga_reportUncaughtExceptions">true</bool>

<!-- How long a session exists before giving up -->
<integer name="ga_sessionTimeout">-1</integer>

<!-- If ga_autoActivityTracking is enabled, an alternate screen name can be specified to substitute for the full length canonical Activity name in screen view hit. In order to specify an alternate screen name use an <screenName> element, with the name attribute specifying the canonical name, and the value the alias to use instead. -->
<screenName name="com.mycompany.MyActivity">My Activity</screenName>
</resources>

That’s all the basic xml configuration done.

Step 4.

We can now add (or modify) your application’s ‘Application’ class so it contains some Trackers that we can reference from our activity…


package com.mycompany;

import android.app.Application;

import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.Tracker;

import java.util.HashMap;

public class MyApplication extends Application {

// The following line should be changed to include the correct property id.
private static final String PROPERTY_ID = "UX-XXXXXXXX-X";

//Logging TAG
private static final String TAG = "MyApp";

public static int GENERAL_TRACKER = 0;

public enum TrackerName {
APP_TRACKER, // Tracker used only in this app.
GLOBAL_TRACKER, // Tracker used by all the apps from a company. eg: roll-up tracking.
ECOMMERCE_TRACKER, // Tracker used by all ecommerce transactions from a company.
}

HashMap<TrackerName, Tracker> mTrackers = new HashMap<TrackerName, Tracker>();

public MyApplication() {
super();
}

synchronized Tracker getTracker(TrackerName trackerId) {
if (!mTrackers.containsKey(trackerId)) {

GoogleAnalytics analytics = GoogleAnalytics.getInstance(this);
Tracker t = (trackerId == TrackerName.APP_TRACKER) ? analytics.newTracker(R.xml.app_tracker)
: (trackerId == TrackerName.GLOBAL_TRACKER) ? analytics.newTracker(PROPERTY_ID)
: analytics.newTracker(R.xml.ecommerce_tracker);
mTrackers.put(trackerId, t);

}
return mTrackers.get(trackerId);
}
}

Either ignore the ECOMMERCE_TRACKER or create an xml file in res/xml called ecommerce_tracker.xml to configure it. I’ve left it in the code just to show its possible to have additional trackers besides APP and GLOBAL. There is a sample xml configuration file for the ecommerce_tracker in <your-android-sdk-directory>\extras\google\google_play_services\samples\analytics\res\xml but it simply contains the tracking_id property discussed earlier.

Step 5.

At last we can now add some actual hit tracking code to our activity. First, import the class com.google.android.gms.analytics.GoogleAnalytics and initialise the application level tracker in your activities onCreate() method. Do this in each activity you want to track.


//Get a Tracker (should auto-report)
((MyApplication) getApplication()).getTracker(MyApplication.TrackerName.APP_TRACKER);

Then, in onStart() record a user start ‘hit’ with analytics when the activity starts up. Do this in each activity you want to track.


//Get an Analytics tracker to report app starts and uncaught exceptions etc.
GoogleAnalytics.getInstance(this).reportActivityStart(this);

Finally, record the end of the users activity by sending a stop hit to analytics during the onStop() method of our Activity. Do this in each activity you want to track.


//Stop the analytics tracking
GoogleAnalytics.getInstance(this).reportActivityStop(this);

And Finally…

If you now compile and install your app on your device and start it up, assuming you set ga_logLevel to verbose and ga_dryRun to false, in logCat you should see some of the following log lines confirming your hits being sent to Google Analytics.


com.mycompany.myapp V/GAV3? Thread[GAThread,5,main]: connecting to Analytics service
com.mycompany.myapp V/GAV3? Thread[GAThread,5,main]: connect: bindService returned false for Intent { act=com.google.android.gms.analytics.service.START cmp=com.google.android.gms/.analytics.service.AnalyticsService (has extras) }
com.mycompany.myapp V/GAV3? Thread[GAThread,5,main]: Loaded clientId
com.mycompany.myapp I/GAV3? Thread[GAThread,5,main]: No campaign data found.
com.mycompany.myapp V/GAV3? Thread[GAThread,5,main]: Initialized GA Thread
com.mycompany.myapp V/GAV3? Thread[GAThread,5,main]: putHit called
...
com.mycompany.myapp V/GAV3? Thread[GAThread,5,main]: Dispatch running...
com.mycompany.myapp V/GAV3? Thread[GAThread,5,main]: sent 1 of 1 hits

Even better, if you’re logged into the Google Analytics console’s reporting dashboard, on the ‘Real Time – Overview’ page, you may even notice the following…

Real Time Overview page
Analytics Real Time Overview page

Next time…

In my next post I’ll show you how to use event tracking to gain extra feedback your users.

About the Author

Ben Wilcock is author of Trip Computer, the only distance tracking app for Android with a LOW POWER mode. It’s perfect for cyclists, runners, walkers, hand-gliders, pilots and drivers. It’s free! Download it from the Google Play Store now:-

Get Trip Computer on Google Play

Announcing: Trip Computer for Android


The reason that I’ve been so bad a posting recently is that I caught the Android development bug. I’ve been using all my spare time working on a new Android application called ‘Trip Computer’.

Trip Computer is a cost and distance tracker that you can use to help with business mileage expenses, or for leisure any time you want to know how far you’ve travelled, which direction you’ve been going in or how long you’ve been going. You can use it walking, cycling, running, in the car, on the train or even on boats or planes (subject to the usual flight restrictions).

TripComputer-app-framed-shadow

Working with Android has been the most brilliant experience, it really is very cool. I’ve also been exclusively using the new Android Studio IDE from Google (pre-beta) including it’s built in Gradle build system.

Android Studio is really good. Announced at last years Google I/O conference it’s based on IntelliJ Idea Community Edition and already it’s giving Eclipse a real run for its money with its strong integration into the Android eco-system. The learning curve has been quite forgiving and the IDE quality and stability are very surprising considering its not a fully released product.

Gradle is a different story. I can take it or leave it to be honest. As a Maven user, I can see lots of issues and nasty cludges (like the poor file ‘filter’ and replace experience which is really useful and much better in Maven). The learning curve has been steep, possibly because Android projects are not standard Java projects. But no pain no gain as they say and I do feel like I’ve come out the other side stronger and more flexible as a result.

I did pick up some handy Android hints and tips along the way, which no doubt I’ll share when I get more time.

You can download the full app for free and try it out for yourself. It’s fairly simple in UI / UX terms, but hopefully it’s got enough features to be a fun addition you your phone or tablet. I’ve tried to support the widest range of devices possible so anything with Froyo onwards and the right hardware should be just fine…

Get it on Google Play