AOSP Expert & Production Engineering
3 min read

Mockito in AOSP

Mocking System Services for Unit Tests

Testing AOSP framework components is notoriously difficult because they often rely on a deep web of system services (e.g., ActivityManagerService, PowerManagerService). Mockito allows you to isolate the class under test by replacing these heavy dependencies with controllable mock objects.

In AOSP, you typically include Mockito in your Android.bp test module using the mockito-target-extended-minus-junit4 static library.

Mock, Spy, ArgumentCaptor

Mockito provides three primary tools for manipulating objects in tests:

  • Mock: Creates a completely empty shell of a class or interface. By default, all methods return null, zero, or false. You explicitly define the behavior of the methods you care about.
  • Spy: Wraps a real object. Method calls pass through to the real implementation unless you explicitly mock them. This is useful for partial mocking.
  • ArgumentCaptor: Allows you to intercept and inspect the exact parameters passed to a mocked method.
import static org.mockito.Mockito.*;

public class BatteryMonitorTest {
    @Test
    public void testBatteryLowAlert() {
        // Create a mock Intent
        Intent mockIntent = mock(Intent.class);
        when(mockIntent.getAction()).thenReturn(Intent.ACTION_BATTERY_LOW);

        // Spy on the object under test to verify internal method calls
        BatteryMonitor monitor = spy(new BatteryMonitor());
        
        monitor.onReceive(mockContext, mockIntent);

        // Verify that the alert method was called
        verify(monitor).triggerLowBatteryAlert();
    }
}

Testing Binder Services with Mockito

Many AOSP components communicate via Binder IPC. Mocking Binder interfaces directly can be complex due to the native layer involvement.

Instead of mocking the native Binder proxy, the standard practice is to mock the Java interface generated from the .aidl file.

// Mocking an AIDL generated interface
IPackageManager mockPackageManager = mock(IPackageManager.class);

// Stubbing a method that throws a RemoteException
when(mockPackageManager.getPackageUid("com.example.app", 0, 0))
    .thenReturn(10050);

By injecting this mockPackageManager into your framework class, you can test how your code handles various package states without needing a running system server.

ExtendedMockito for Static Mocking

Standard Mockito cannot mock static methods, final classes, or constructors. This is a massive hurdle in AOSP, where utility classes like SystemProperties or Settings.Global are ubiquitous.

To solve this, AOSP leverages ExtendedMockito (built on top of dexmaker-mockito-inline).

import com.android.dx.mockito.inline.extended.ExtendedMockito;
import org.mockito.MockitoSession;

public class SystemPropTest {
    private MockitoSession mSession;

    @Before
    public void setUp() {
        // Initialize static mocking for android.os.SystemProperties
        mSession = ExtendedMockito.mockitoSession()
            .mockStatic(SystemProperties.class)
            .startMocking();
    }

    @After
    public void tearDown() {
        mSession.finishMocking();
    }

    @Test
    public void testFeatureFlag() {
        // Stub the static method
        ExtendedMockito.doReturn("true")
            .when(() -> SystemProperties.get("ro.feature.enabled", "false"));

        // Now test your code that reads this property
        assertTrue(FeatureManager.isEnabled());
    }
}

Note: Static mocking introduces performance overhead and potential test pollution. Always ensure the MockitoSession is properly closed in the @After teardown method.