Mock final and static methods on Android devices

Philip P. Moltmann
Android Developers
Published in
3 min readAug 20, 2018
Photo by Steven Lewis

tl;dr:

With Android P a developer can mock final classes and stub final and static methods. This will allow tests to directly run against classes that were previously unmockable.

About Mockito

Mockito is a popular mocking library for Java. A developer can use it to intercept method calls and replace them with alternate behavior:

Such a method behavior replacement is referred to as “stubbing a method”.

Further the Mockito method spy creates stubbable clones of the original objects. The fields of the spy-objects are copies of the original’s fields and the methods of the spy-object can be stubbed:

Using Mockito’s plugin system certain components of Mockito can be replaced. E.g. mockito-android and dexmaker-mockito replace the regular mock-generation component with one capable of generating mocks that work on Android devices. Let’s use the term “Mockito variant” to talk about Mockito libraries with replaced components.

All variants support the same API, i.e. mock, spy, when, verify etc… .

Stubbing final methods

Regular Mockito mocks and spies are implemented as subclasses of the mocked classes. The all intercepting code lives in methods that override the original methods. Hence initially only non-final instance methods could be stubbed.

Since Mockito 2.1.0 the Mockito variant mockito-inline allows a developer to stub final methods too:

As final methods can’t be overridden the mock-generation code of mockito-inline modifies the byte code of the mocked class and inlines the intercepting code directly into the original methods.

mockito-inline implements support for stubbing final methods for Java byte code based runtimes. The Android runtime uses Dalvik byte code, hence this variant does not work for Android.

The Mockito variant dexmaker-mockito-inline can inline the method call intercepting code into the Dalvik byte code of the original classes by using the improved JVMTI functionality added in Android P.

JVMTI is an interface between apps and the runtime. It allows deep introspection and manipulation of the current app. Currently the app needs to be marked as android:debuggable to use JVMTI. Hence dexmaker-mockito-inline requires the app to marked as be debuggable.

Before Android P the JVMTI support was not sufficient for the needs of dexmaker-mockito-inline. Hence the new mocking features require at least Android P.

Android specific enhancements

The same byte code modification used for final methods can be used to allow the developer to stub static methods. The Mockito API does not provide interfaces to stub static methods yet, hence new interfaces need to be added.

The biggest difference from regular instance-stubbing is that there is no natural place to reset the stubbing of a static method. To define a scope the Mockito variant dexmaker-mockito-inline-extended extends Mockito sessions to define the scope of the mocking. dexmaker-mockito-inline-extended is an extension of dexmaker-mockito-inline, hence the same restrictions apply.

In Android certain objects are created by the system. Hence it is not easy to intercept the creation of such objects. The most prominent of these kind of objects are probably the Activity objects.

To address this problem dexmaker-mockito-inline-extended adds the method spyOn that converts the existing object into a spy.

The full description of the added functionality is available on github.

Comparison of Mockito variants for Dalvik byte code based runtimes

--

--