How make mock of final class?

落花浮王杯 提交于 2019-12-11 08:21:37

问题


Work in AndroidStudio. Want make mock of final class for AndroidInstrumentalTest with PowerMock. Added libs in gradle:

 androidTestCompile ('org.powermock:powermock-api-mockito:1.5.6')
 androidTestCompile ('org.powermock:powermock-core:1.5.6')
 androidTestCompile ('org.powermock:powermock-module-junit4:1.5.6')
 androidTestCompile 'org.mockito:mockito-core:1.10.8'
 androidTestCompile 'com.google.dexmaker:dexmaker:1.1'
 androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.1'

Make test class:

public class BluetoothTest extends ActivityInstrumentationTestCaseWithLogIn<PlanActivity> {


 public BluetoothTest() {
    super(PlanActivity.class);
 }


  @Override
  public void setUp() throws Exception{
        super.setUp();          
        BluetoothGatt gatt = PowerMockito.mock(BluetoothGatt.class);
  }
}

Stack trace:

 java.lang.VerifyError: org/mockito/cglib/core/ReflectUtils
at org.mockito.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:167)
at org.mockito.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:217)
at org.mockito.cglib.core.KeyFactory$Generator.create(KeyFactory.java:145)
at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:117)
........
at android.support.test.internal.runner.junit3.JUnit38ClassRunner.run(JUnit38ClassRunner.java:90)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:24)
........
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at org.junit.runner.JUnitCore.run(JUnitCore.java:136)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:270)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1732)

I checked solutions from this issue, with no luck. Apparently solutions help with mockito-core, not powermock. It proved by another issue

I saw docs, then try added annotations @RunWith(PowerMockRunner.class) and @PrepareForTest(BluetoothGatt.class) on test class. Result :

   java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
    at org.powermock.modules.junit4.common.internal.impl.JUnitVersion.getJUnitVersion(JUnitVersion.java:28)
    at org.powermock.modules.junit4.common.internal.impl.JUnitVersion.isGreaterThanOrEqualTo(JUnitVersion.java:23)
    at org.powermock.modules.junit4.PowerMockRunner.getRunnerDelegateImplClass(PowerMockRunner.java:38)
    at org.powermock.modules.junit4.PowerMockRunner.<init>(PowerMockRunner.java:33)
   ........
    at org.junit.runner.Computer.getSuite(Computer.java:26)
    at android.support.test.internal.runner.TestRequestBuilder.classes(TestRequestBuilder.java:598)
    at android.support.test.internal.runner.TestRequestBuilder.build(TestRequestBuilder.java:578)
    at android.support.test.runner.AndroidJUnitRunner.buildRequest(AndroidJUnitRunner.java:542)
    at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:269)
    at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1732)

回答1:


On non-rooted devices, APKs are subject to "verification", where the VM ensures that classes refer only to the implementations they are compiled against. Emulators and rooted devices aren't subject to this rule.

Unfortunately, implementations that hack classloaders (PowerMock and Robolectric) almost always violate that rule, because they create unexpected static class and method implementations (in order to mock them).

Keep the classloader hacking to your JVM unit tests, not your instrumentation tests, and instead extract any relevant interfaces into a wrapper you can control (and mock).




回答2:


Have you tried using Robolectric + Mockito?.

I believe you have the right idea. It should be as simple as:

BluetoothGatt gatt = mock(BluetoothGatt.class);

Please take a look at this example:

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

private BluetoothGattCharacteristic characteristic;
private OnBoardingService service;
private BluetoothGattReceiver receiver = new BluetoothGattReceiver();

@Before 
public void initialise() {
    BleDevice bleDevice = mock(BleDevice.class);
    when(bleDevice.getType()).thenReturn(BleDeviceType.WunderbarMIC);
    BluetoothGatt gatt = mock(BluetoothGatt.class);
    BluetoothGattService gattService = mock(BluetoothGattService.class);
    when(gatt.getServices()).thenReturn(Arrays.asList(gattService));
    when(gattService.getUuid()).thenReturn(fromString("00002001-0000-1000-8000-00805f9b34fb"));
    characteristic = mock(BluetoothGattCharacteristic.class);
    when(gattService.getCharacteristics()).thenReturn(Arrays.asList(characteristic));

    service = new OnBoardingService(bleDevice, gatt, receiver);
}

Source: https://github.com/relayr/android-sdk/blob/master/tests/src/androidTest/java/io/relayr/ble/service/OnBoardingServiceTest.java https://github.com/relayr/android-sdk/blob/master/tests/src/androidTest/java/io/relayr/ble/service/BluetoothGattReceiverTest.java



来源:https://stackoverflow.com/questions/29311445/how-make-mock-of-final-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!