Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to combine PowerMock and Robolectric

I have a static method that checks for internet status, that uses a Context. So to mock it i need to use PowerMock. I am using robolectric to speed up my test since the only thing i need mocked is the mocked. But i cant seem to configure PowerMock(1.6.6) and Robolectric(3.2.2) to work together. This is how i annotate my class:

@RunWith(RobolectricTestRunner.class)
@org.robolectric.annotation.Config(constants = BuildConfig.class, sdk = 21)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
@PrepareForTest({Utils.class})

and this line in the setup method:

PowerMockito.mockStatic(Utils.class);

But i receive this exception:

org.powermock.api.mockito.ClassNotPreparedException: 
The class com.zeyad.usecases.data.utils.Utils not prepared for test.
To prepare this class, add class to the '@PrepareForTest' annotation.
In case if you don't use this annotation, add the annotation on class or  method level. 

at org.powermock.api.mockito.expectation.reporter.MockitoPowerMockReporter.classNotPrepared(MockitoPowerMockReporter.java:32)
at org.powermock.api.mockito.internal.mockcreation.MockTypeValidatorFactory$DefaultMockTypeValidator.validate(MockTypeValidatorFactory.java:38)
at org.powermock.api.mockito.internal.mockcreation.AbstractMockCreator.validateType(AbstractMockCreator.java:10)
at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.createMock(DefaultMockCreator.java:56)
at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.mock(DefaultMockCreator.java:46)
at org.powermock.api.mockito.PowerMockito.mockStatic(PowerMockito.java:71)
at com.zeyad.usecases.data.repository.stores.DataStoreFactoryJUnitTest.setUp(DataStoreFactoryJUnitTest.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:339)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:259)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:41)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:199)

My build.gradle file dependencies:

testCompile "junit:junit:$junit"
testCompile "org.hamcrest:hamcrest-library:$hamcrest"
testCompile "com.android.support:support-annotations:$supportLibraryVersion"
testCompile "org.mockito:mockito-core:1.10.19"
testCompile "org.robolectric:robolectric:$robolectric"
testCompile "org.robolectric:shadows-support-v4:$robolectric"
testCompile "org.powermock:powermock-module-junit4:$powerMock"
testCompile "org.powermock:powermock-module-junit4-rule:$powerMock"
testCompile "org.powermock:powermock-api-mockito:$powerMock"
testCompile "org.powermock:powermock-classloading-xstream:$powerMock"
like image 567
Zeyad Gasser Avatar asked Oct 29 '22 12:10

Zeyad Gasser


2 Answers

On Robolectric wiki you may find a full instruction how to setup Roboeletric with PowerMock https://github.com/robolectric/robolectric/wiki/Using-PowerMock

like image 126
Arthur Zagretdinov Avatar answered Nov 14 '22 07:11

Arthur Zagretdinov


Sometimes the answer is to simply step back and look into your "need" to use PowerMock.

So, you have a static method that needs PowerMock to be testable?!

Then, simply avoid making that code static. And then, your need to use PowerMock just vanishes.

Simple replace it with a combination of an interface, impl class (and maybe an enum singleton if you need "exactly" one implementation of it).

I guarantee you: not needing PowerMock is the much better option; compared to spending many hours to get it work with another ByteCode-manipulating framework.

Or in other words: learn how to write testable code, and do that; instead of creating hard-to-test code, that requires the big PowerMock hammer to become testable. Watch these videos to learn how to do that.

I am not an expert for RoboElectric, but I assume: you problem could very well be that both frameworks need their own specific @Runner to work. Thus: maybe this here helps; as the answers suggests a way to use PowerMock without using the PowerMockRunner.

like image 26
GhostCat Avatar answered Nov 14 '22 06:11

GhostCat