简体   繁体   中英

Android Instrumented Test, Mock Final Classes

How to mock final classes inside Android Instrumented Test cases, that is mocking final classes inside Android Run Time ?

(I am using Mockito 2.X )

I have a test case like follows -

import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;

import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {

    // This is my app specific NON - Final class
    private ShutdownServicesReqSig rebootSig = ShutdownServicesReqSig.newBuilder(ShutDownType.REBOOT_SYSTEM).setReason("test").build();

    private PowerManager mockedPowerManager = null;

    private Context mockedContext = null;


    @Test
    public void testRestart() throws InterruptedException
    {

        mockedContext = Mockito.mock(Context.class);

        mockedPowerManager = Mockito.mock(PowerManager.class);  // Here is the problem android.os.PowerManager is a Final class in latest Android SDK
                                                        // I need to mock it, only then I can use Mockito.verify() on PowerManager

        Mockito.when(mockedContext.getSystemService(Context.POWER_SERVICE)).thenReturn(mockedPowerManager);

        assertTrue(executor.requestShutdown(rebootSig));

        Thread.sleep(1000);

        Mockito.verify(mockedPowerManager).reboot(any(String.class)); // Mocking of PowerManager is essential to be sure of method call on PowerManager, using Mockito.verify 

        Mockito.reset(mockedPowerManager);
    }
}

When I am running it as Android Instrumented Test on ART (placing inside - MyApplication\\app\\src\\androidTest ), I am getting following error -

org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class android.os.PowerManager
Mockito cannot mock/spy following:
- final classes
- anonymous classes
- primitive types

But, the same code, when I am running as a normal JUnit test, inside JVM (placing inside - MyApplication\\app\\src\\test ) it is working perfectly fine.

I need to run it inside ART , as I like to test some of my customized Android Services, and I need to mock final classes like PowerManager , as only then I can use Mockito.verify() on PowerManager , to verify certain method calls on PowerManager .

Help/guides are appreciated.

Mockito 2 has an "opt-in" mechanism to enable mocking of final methods or classes, see here . You enable it via the mockito extension mechanism by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:

mock-maker-inline

(well, that file needs to be in the class path).

If that works for you, perfect. If not, there is probably nothing else you can do.

You see, instrumenting boils down to: manipulating byte code. Typically, it doesn't work out to use more than one framework doing that.

Meaning: in order to enable that kind of mocking, bytecode needs to be manipulated. And for obvious reasons, getting two different bytecode manipulation frameworks to nicely coexist is a very tough challenge.

Long story short: try that extension mechanism, when it doesn't work you have to step back and ask yourself: what exactly is the final goal I intend to achieve?!

Most likely, you probably shouldn't waste your time trying to mock things running within ART.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM