Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISSUE - Unit test Problem (librealm-jni.so) #3808

Closed
pouyabs5 opened this issue Nov 16, 2016 · 33 comments
Closed

ISSUE - Unit test Problem (librealm-jni.so) #3808

pouyabs5 opened this issue Nov 16, 2016 · 33 comments
Labels

Comments

@pouyabs5
Copy link

When i want to run this simple unit test :

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 19)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
@PrepareForTest({Realm.class, RealmLog.class})

public class ExampleUnitTest {

    @Rule
    public PowerMockRule rule = new PowerMockRule();
    Realm mockRealm;

    @Before
    public void setup() throws Exception {

        mockStatic(Realm.class);
        mockStatic(RealmLog.class);

        Realm mockRealm = PowerMockito.mock(Realm.class);

        when(Realm.getDefaultInstance()).thenReturn(mockRealm);
        when(Realm.getDefaultInstance()).thenReturn(mockRealm);
        this.mockRealm = mockRealm;
    }

    @Test
    public void shouldBeAbleToGetDefaultInstance() {
        assertThat(Realm.getDefaultInstance(), is(mockRealm));
    }
}

I face this error :

java.lang.UnsatisfiedLinkError: Can't load library: /tmp/android-tmp-robolectric2838690925023503406/app_lib/librealm-jni.so

and indicates to the error line in my class that extends from Application where i init the realm :

Realm.init(getApplicationContext());
        RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().deleteRealmIfMigrationNeeded().build();
        Realm.setDefaultConfiguration(realmConfiguration);
@zaki50
Copy link
Contributor

zaki50 commented Nov 17, 2016

The only way to work around it for now is set RealmCore#libraryIsLoaded to true before calling Realm#init(Context) by using reflection.

@nikiJava
Copy link

zaki50, would you discribe, how can I do this by reflecting? I have such problem. I just had to add RealmCore.loadLibrary(this) in my application class before calling Realm.init(this), yes?

@cmelchior
Copy link
Contributor

@pouyabs5
Copy link
Author

@zaki50, i set RealmCore#libraryIsLoaded before calling Realm#init(context) but i still face same error and when i debug the RealmConfig.loadLibrary() functions, the issue is for this :
java.lang.UnsatisfiedLinkError: no realm-jni in java.library.path

@kneth
Copy link
Contributor

kneth commented Nov 21, 2016

Please take a look at robolectric/robolectric#1389

@pouyabs5
Copy link
Author

I created this project :
https://github.com/pouyabs5/realm-test.git
after running unit test i face to this:
Failed to transform class with name io.realm.Realm. Reason: rx.Observable

@Zhuinden
Copy link
Contributor

Ah, you should create a package named rx, and you should create an empty class inside it called Observable

package rx;

public class Observable {
}

@nikiJava
Copy link

I'm getting this Exception when my test is running:

java.lang.UnsatisfiedLinkError: Can't load library: C:\Users\Nikita\AppData\Local\Temp\android-tmp-robolectric8414149647152901922\app_lib\realm-jni.dll

	at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1827)
	at java.lang.Runtime.load0(Runtime.java:809)
	at java.lang.System.load(System.java:1086)
	at com.getkeepsafe.relinker.SystemLibraryLoader.loadPath(SystemLibraryLoader.java:29)
	at com.getkeepsafe.relinker.ReLinkerInstance.loadLibraryInternal(ReLinkerInstance.java:198)
	at com.getkeepsafe.relinker.ReLinkerInstance.loadLibrary(ReLinkerInstance.java:136)
	at com.getkeepsafe.relinker.ReLinker.loadLibrary(ReLinker.java:70)
	at com.getkeepsafe.relinker.ReLinker.loadLibrary(ReLinker.java:51)
	at io.realm.internal.RealmCore.loadLibrary(RealmCore.java:59)
	at io.realm.Realm.init(Realm.java:187)
	at com.tst.nikita.newsapp.presentation.NewsApplication.onCreate(NewsApplication.java:41)
	at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:141)
	at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:234)
	at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:171)
	at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:47)
	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:137)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
	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 com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)


Process finished with exit code -1

I did my method setUp() like here https://github.com/realm/realm-java/blob/master/examples/unitTestExample/src/test/java/io/realm/examples/unittesting/ExampleActivityTest.java but Realm.init(Context context) in my Application.class is running and I'm gettin this Exception.

My test class:

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
@PowerMockIgnore({ "org.robolectric.*", "org.mockito.*", "android.*"})
@SuppressStaticInitializationFor("io.realm.internal.Util")
@PrepareForTest({Realm.class, RealmConfiguration.class, RealmQuery.class, RealmResults.class, RealmCore.class, RealmLog.class})
public class RealmCacheTest {

    Realm mockRealm;

    @Rule
    public PowerMockRule rule = new PowerMockRule();

    @Before
    public void setUp() throws Exception {

        mockStatic(RealmCore.class);
        mockStatic(RealmLog.class);
        mockStatic(Realm.class);
        mockStatic(RealmConfiguration.class);
        RealmCore.loadLibrary((RuntimeEnvironment.application));
        Realm.init(RuntimeEnvironment.application);

        final Realm mockRealm = mock(Realm.class);
        final RealmConfiguration mockRealmConfig = mock(RealmConfiguration.class);
     
        doNothing().when(RealmCore.class);
        whenNew(RealmConfiguration.class).withAnyArguments().thenReturn(mockRealmConfig);

        when(Realm.getDefaultInstance()).thenReturn(mockRealm);
        this.mockRealm = mockRealm;
    }

    @Test
    public void shouldBeAbleToGetDefaultInstance() {
        assertThat(Realm.getDefaultInstance(), is(mockRealm));
    }
}

@beeender
Copy link
Contributor

Since you mocked everything, no need to call RealmCore.loadLibrary((RuntimeEnvironment.application)); and Realm.init(RuntimeEnvironment.application); . Will it work if you remove those two lines?

@thorbenprimke
Copy link

I ran into the same / similar issue. After upgrading to Realm 2.x, a lot of robolectic tests failed. The root cause was the Realm.init addition to the Application.

Since I didn't want to touch any of the tests, I ended up using reflection to make Realm.init think it is already initialized. Setting libraryIsLoaded to true was not enough - it was still causing exceptions.

Thoughts on this approach?
For me the above mentioned mock approach with mockStatic/PrepareForTest only worked with PowerMockRule and not with MockitoRule.

Here is the code snippet to fake init Realm.

package io.realm;

import android.content.Context;
import java.lang.reflect.Field;

public class FakeRealmInitForTestEnvironment {

    public static void init(Context context) {
        try {
            Field applicationContext = BaseRealm.class.getDeclaredField("applicationContext");
            applicationContext.set(applicationContext, context);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

@kneth
Copy link
Contributor

kneth commented Dec 5, 2016

@pouyabs5 @nikiJava Did suggestion by @thorbenprimke help you?

@pouyabs5
Copy link
Author

pouyabs5 commented Dec 5, 2016

@kneth unfortunately no!

@cmelchior
Copy link
Contributor

@pouyabs5 Not entirely sure what you are doing differently, but I running the unit tests from https://github.com/realm/realm-java/blob/master/examples/unitTestExample/src/test/java/io/realm/examples/unittesting/ExampleRealmTest.java seems to work fine. So I would probably start by comparing those with what you are doing to see if you can spot the difference.

Note that we recently merged a small change to master that removes the final modifier from all public API classes. This should make mocking with Mockito a lot easier.

@reline
Copy link

reline commented Jan 3, 2017

I am using the example that @cmelchior just pointed out and originally I had Realm.init(getApplicationContext()) in my Application class, but after moving that line to the first activity of my app it solved this issue.

@kneth
Copy link
Contributor

kneth commented Jan 4, 2017

@pouyabs5 Can you try to move Realm.init() as @reline suggests?

@kneth
Copy link
Contributor

kneth commented Jan 25, 2017

I assume that removing Realm.init() solved your issue.

@erudonja1
Copy link

erudonja1 commented Apr 20, 2017

No, it still not working...

I tried everything for testing Realm with unit testing and now I'm even thinking about remove Realm from project at all because there is no way that I could test my functionalities or services with unit tests and there already was few more issues. I don't understand how/why other people and you guys from Realm didn't take care about this.

I 've lost like 3 weeks searching for solution, and I've lost my patience about this framework and testing. This is not professional solution for ORM for Android.
In project I use also Dagger, and I've tried even to init Realm with some inMemory configuration, but Realm.init is not working with RuntimeEnvironment.application etc.

This is my test class with some stupid case:

@RunWith(RobolectricTestRunner.class)
@config(application = TestApp.class, constants = BuildConfig.class, sdk = 21)
@PowerMockIgnore({ "org.robolectric.", "org.mockito.", "android.*"})
@SuppressStaticInitializationFor("io.realm.internal.Util")
@PrepareForTest({Realm.class, RealmConfiguration.class, RealmQuery.class, RealmResults.class, RealmCore.class, RealmLog.class})
public class DocumentServiceTest {

Realm mockRealm;

@Rule
public PowerMockRule rule = new PowerMockRule();

@Before
public void setUp() throws Exception {

    mockStatic(RealmCore.class);
    mockStatic(RealmLog.class);
    mockStatic(Realm.class);
    mockStatic(RealmConfiguration.class);
    RealmCore.loadLibrary((RuntimeEnvironment.application));
  //  Realm.init(RuntimeEnvironment.application);

    final Realm mockRealm = mock(Realm.class);
    final RealmConfiguration mockRealmConfig = mock(RealmConfiguration.class);

    doNothing().when(RealmCore.class);
    whenNew(RealmConfiguration.class).withAnyArguments().thenReturn(mockRealmConfig);

    when(Realm.getDefaultInstance()).thenReturn(mockRealm);
    this.mockRealm = mockRealm;
}

@Test
public void shouldBeAbleToGetDefaultInstance() {
    assertThat(Realm.getDefaultInstance(), is(mockRealm));
}

@Test
public void showsCorrectBillValue() {
    SharedService sharedService = Mockito.mock(SharedService.class);

    DocumentService documentService = new DocumentService(mockRealm, sharedService);
    Document d = new Document();
    documentService.saveDocument(d);

    DocumentItem documentItem1 = new DocumentItem();
    documentItem1.setKolicina(10.0);
    documentItem1.setNetoCijena(10.0);

    DocumentItem documentItem2 = new DocumentItem();
    documentItem2.setKolicina(10.0);
    documentItem2.setNetoCijena(10.0);

    DocumentItem documentItem3 = new DocumentItem();
    documentItem3.setKolicina(10.0);
    documentItem3.setNetoCijena(10.0);

    d.getDocumentItems().add(documentItem1);
    d.getDocumentItems().add(documentItem2);
    d.getDocumentItems().add(documentItem3);

    String result = documentService.getDocumentBillValue(d);

    assertThat(result, is("300.00"));
}

}

This throws some errors:

com.thoughtworks.xstream.converters.ConversionException: Cannot convert type com.sun.org.apache.xerces.internal.dom.DeferredElementImpl to type org.w3c.dom.Node
---- Debugging information ----
message : Cannot convert type com.sun.org.apache.xerces.internal.dom.DeferredElementImpl to type org.w3c.dom.Node
class : org.robolectric.manifest.AndroidManifest
required-type : org.robolectric.manifest.AndroidManifest
converter-type : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
path : /org.powermock.modules.junit4.rule.PowerMockStatement$1/outer-class/fNext/next/val$roboMethod/appManifest/applicationNode
line number : 5101
class[1] : org.robolectric.RobolectricTestRunner$RobolectricFrameworkMethod
class[2] : org.robolectric.RobolectricTestRunner$HelperTestRunner$1
class[3] : org.junit.internal.runners.statements.RunBefores
class[4] : org.powermock.modules.junit4.rule.PowerMockStatement
class[5] : org.powermock.modules.junit4.rule.PowerMockStatement$1
version : not available

and here is the gradle dependencies:

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])

// DAGGER
compile "com.google.dagger:dagger:2.9"
apt "com.google.dagger:dagger-compiler:2.9"
testApt 'com.google.dagger:dagger-compiler:2.9'
androidTestApt 'com.google.dagger:dagger-compiler:2.9'
provided 'javax.annotation:jsr250-api:1.0'

// TESTING
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
    exclude group: 'com.android.support', module: 'support-annotations'
})
androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'

testCompile 'junit:junit:4.12'
testCompile "org.robolectric:robolectric:3.3"
testCompile 'org.mockito:mockito-core:2.7.22'
testCompile 'org.robolectric:shadows-support-v4:3.3'
testCompile 'org.powermock:powermock-module-junit4:1.6.5'
testCompile 'org.powermock:powermock-module-junit4-rule:1.6.5'
testCompile 'org.powermock:powermock-api-mockito:1.6.5'
testCompile 'org.powermock:powermock-classloading-xstream:1.6.5'

//DESIGN
compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.android.support:design:24.2.1'
compile 'com.github.ganfra:material-spinner:1.1.1'

//GSON & RETROFIT
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'

//FIREBASE
compile 'com.google.firebase:firebase-core:10.0.1'
compile 'com.google.firebase:firebase-messaging:10.0.1'
compile 'com.google.firebase:firebase-crash:10.0.1'

}

I DON'T GET IT REALLY, is there any way that I could test my services that uses 1 argument(Realm db).???

If not, than this solution(REALM) for mobile database, for some serious application is BAD....

@Zhuinden
Copy link
Contributor

Zhuinden commented Apr 20, 2017

com.thoughtworks.xstream.converters.ConversionException: Cannot convert type

This is an error in Robolectric 's classloading in conjunction with Powermock, see robolectric/robolectric#2208

(although it should have been fixed by 3.3....)

@erudonja1
Copy link

Ok, If I can't test this with Robolectric, what should I do then? I should test it with what? (Mockito, JUnit...)

Is there any complete solution for unit testing?

@cmelchior
Copy link
Contributor

@erudonja1 Please keep a civil tone (https://realm.io/conduct/ ). We all know it is frustrating if things do not work, but yelling will not get you anywhere.

Did you see our unit testing example which uses Robolectric: https://github.com/realm/realm-java/blob/master/examples/unitTestExample/src/test/java/io/realm/examples/unittesting/ExampleRealmTest.java

Note that in recent releases all our public classes are no longer final which means they should be mockable my Mockito.

@Zhuinden
Copy link
Contributor

Zhuinden commented Apr 20, 2017

@cmelchior i think that works because it uses testCompile "org.robolectric:robolectric:3.0", and robolectric 3.1+ broke something with their classloading that it seems they still haven't seem to have properly fixed when used in conjunction with Powermock.

Personally I could never get Robolectric to work in any slightly more complex setting, with or without Realm. -_-

Anyways, if Realm's static accessor methods Realm.getDefaultInstance() are wrapped with something interface-y then PowerMock isn't needed, and testing should work. This issue stems from Robolectric not interacting properly with PowerMock, after all.

@erudonja1
Copy link

erudonja1 commented Apr 20, 2017

@cmelchior Don't worry, I'm not yelling at anyone, read my comment again, there is no "!!!" anywhere. The accent is in that I don't really understand how I could test my functionalities at all now. This should be your problem No.1 if you plan to use/recommend this ORM somewhere for professional usage. It's not like I have one solution for testing and I didn't make it. The frustration begins when you try 10000 different solutions from your comments and even gists that are incomplete, and neither one is working.

And what should I do now?

@erudonja1
Copy link

@Zhuinden are you saying that this solution worked before for some versions?

If it is, could you tell me which and for what version should I use then. please.

@Zhuinden
Copy link
Contributor

Zhuinden commented Apr 20, 2017

@erudonja1 as I said, Robolectric 3.1 broke PowerMock integration. But Robolectric 3.0 is rather old... the xstream thing is what breaks it.

@erudonja1
Copy link

@Zhuinden I'm not so optimistic with that version neither but I'll try tomorrow again.
I hope you were right about this... Thanks

@erudonja1
Copy link

@Zhuinden Nope... It still not working with 3.0 version.

Error message:
com.thoughtworks.xstream.converters.ConversionException:
---- Debugging information ----
cause-exception : java.lang.IllegalStateException
cause-message : Failed to transform class with name io.realm.Realm. Reason: rx.Observable
class : org.junit.internal.runners.statements.InvokeMethod
required-type : org.junit.internal.runners.statements.InvokeMethod
converter-type : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
path : /org.powermock.modules.junit4.rule.PowerMockStatement$1/outer-class/fNext/next/target
line number : 12
class[1] : org.junit.internal.runners.statements.RunBefores
class[2] : org.powermock.modules.junit4.rule.PowerMockStatement
class[3] : org.powermock.modules.junit4.rule.PowerMockStatement$1
version : not available

gradle dependencies:
testCompile 'junit:junit:4.12'
testCompile "org.robolectric:robolectric:3.0"
testCompile 'org.mockito:mockito-core:2.7.22'
testCompile 'org.robolectric:shadows-support-v4:3.0'
testCompile 'org.powermock:powermock-module-junit4:1.6.5'
testCompile 'org.powermock:powermock-module-junit4-rule:1.6.5'
testCompile 'org.powermock:powermock-api-mockito:1.6.5'
testCompile 'org.powermock:powermock-classloading-xstream:1.6.5'

@beeender
Copy link
Contributor

@erudonja1 try to create a dummy class rx.Observable. See https://realm.io/docs/java/latest/#jackson-databind

@erudonja1
Copy link

@beeender but where to put that package and class?
Should I create it into my testProject, androidTestProject or just into my project?

If I just create new package with class as it is mentioned it throws this error message:

java.lang.NoClassDefFoundError: org/mockito/cglib/proxy/Enhancer

at org.powermock.api.extension.proxyframework.ProxyFrameworkImpl.isProxy(ProxyFrameworkImpl.java:52)
at org.powermock.reflect.internal.WhiteboxImpl.getUnmockedType(WhiteboxImpl.java:1689)
at org.powermock.reflect.internal.WhiteboxImpl.getType(WhiteboxImpl.java:2111)
at org.powermock.reflect.internal.WhiteboxImpl.invokeConstructor(WhiteboxImpl.java:1329)
at org.powermock.reflect.Whitebox.invokeConstructor(Whitebox.java:511)
at org.powermock.tests.utils.impl.MockPolicyInitializerImpl.invokeInitializeInterceptionSettingsFromClassLoader(MockPolicyInitializerImpl.java:151)
at org.powermock.tests.utils.impl.MockPolicyInitializerImpl.refreshPolicies(MockPolicyInitializerImpl.java:138)
at org.powermock.modules.junit4.rule.PowerMockStatement$1.run(PowerMockRule.java:82)
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.powermock.reflect.internal.WhiteboxImpl.performMethodInvocation(WhiteboxImpl.java:1899)
at org.powermock.reflect.internal.WhiteboxImpl.doInvokeMethod(WhiteboxImpl.java:801)
at org.powermock.reflect.internal.WhiteboxImpl.invokeMethod(WhiteboxImpl.java:666)
at org.powermock.reflect.Whitebox.invokeMethod(Whitebox.java:401)
at org.powermock.classloading.AbstractClassloaderExecutor.getResult(AbstractClassloaderExecutor.java:69)
at org.powermock.classloading.AbstractClassloaderExecutor.executeWithClassLoader(AbstractClassloaderExecutor.java:59)
at org.powermock.classloading.SingleClassloaderExecutor.execute(SingleClassloaderExecutor.java:67)
at org.powermock.classloading.AbstractClassloaderExecutor.execute(AbstractClassloaderExecutor.java:43)
at org.powermock.modules.junit4.rule.PowerMockStatement.evaluate(PowerMockRule.java:75)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:251)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
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:152)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)

@beeender
Copy link
Contributor

@erudonja1 The exception message shows another problem which I have no idea about ... sounds like something wrong between powermock and robolectric.

@Zhuinden
Copy link
Contributor

Zhuinden commented Apr 21, 2017

@erudonja1 once you fixed issue by creating rx.Observable class, now this problem is a version mismatch between Mockito 2.x and Powermock 1.6.5! see https://groups.google.com/forum/#!topic/powermock/cE4T40Xa_wc

Powermock only has experimental support of Mockito 2.x (in 1.7.0 RC versions), see https://github.com/powermock/powermock/wiki/Mockito-2-(Maven)

The Powermock 2.0 release is scheduled for June 2017.

Another option is to revert to Mockito 1.x.

@erudonja1
Copy link

@Zhuinden @cmelchior @beeender Thank you guys!

SOLUTION
Finally this is solution that works partially:

gradle:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])

// DAGGER
compile "com.google.dagger:dagger:2.9"
apt "com.google.dagger:dagger-compiler:2.9"
testApt 'com.google.dagger:dagger-compiler:2.9'
androidTestApt 'com.google.dagger:dagger-compiler:2.9'
provided 'javax.annotation:jsr250-api:1.0'

// TESTING
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
    exclude group: 'com.android.support', module: 'support-annotations'
})
androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'

testCompile 'junit:junit:4.12'
testCompile "org.robolectric:robolectric:3.0"
testCompile 'org.mockito:mockito-core:1.10.19'
testCompile 'org.robolectric:shadows-support-v4:3.0'
testCompile 'org.powermock:powermock-module-junit4:1.6.5'
testCompile 'org.powermock:powermock-module-junit4-rule:1.6.5'
testCompile 'org.powermock:powermock-api-mockito:1.6.5'
testCompile 'org.powermock:powermock-classloading-xstream:1.6.5'

//DESIGN
compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.android.support:design:24.2.1'
compile 'com.github.ganfra:material-spinner:1.1.1'

//GSON & RETROFIT
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'

//FIREBASE
compile 'com.google.firebase:firebase-core:10.0.1'
compile 'com.google.firebase:firebase-messaging:10.0.1'
compile 'com.google.firebase:firebase-crash:10.0.1'

}

I also needed to create this class and package, somewhere in project root:

package rx;
public class Observable {
}

Then you could setUp before test like this:

@RunWith(RobolectricGradleTestRunner.class)
@config(application = TestApp.class, constants = BuildConfig.class, sdk = 21)
@PowerMockIgnore({ "org.robolectric.", "org.mockito.", "android.*"})
@SuppressStaticInitializationFor("io.realm.internal.Util")
@PrepareForTest({Realm.class, RealmConfiguration.class, RealmQuery.class, RealmResults.class, RealmCore.class, RealmLog.class})
public class DocumentServiceTest {

Realm mockRealm;

@Rule
public PowerMockRule rule = new PowerMockRule();

@Before
public void setUp() throws Exception {

    mockStatic(RealmCore.class);
    mockStatic(RealmLog.class);
    mockStatic(Realm.class);
    mockStatic(RealmConfiguration.class);
    RealmCore.loadLibrary((RuntimeEnvironment.application));
    Realm.init(RuntimeEnvironment.application);

    final Realm mockRealm = mock(Realm.class);
    final RealmConfiguration mockRealmConfig = mock(RealmConfiguration.class);

    doNothing().when(RealmCore.class);
    whenNew(RealmConfiguration.class).withAnyArguments().thenReturn(mockRealmConfig);

    when(Realm.getDefaultInstance()).thenReturn(mockRealm);
    this.mockRealm = mockRealm;
}

}

Also I had to override my application class, onCreate method, because in there I was initializing Dagger...

public class TestApp extends Application {
@OverRide
public void onCreate() {
}
}

CONCLUSION:
Realm.init(RuntimeEnvironment.application) in UnitTest wont' throw error, but will not work either with this piece of code. For example when you try to get some instance of InMemory database in unit test, compiler will say you that Realm.init is not triggered before that.
BUT you can mock database(which is good)! So basically you can use it in constructors but if you try to save something to that database, you will get an error.

Soooooo, test those methods that are not using database directly...(it's better anything than nothing :()

@Zhuinden
Copy link
Contributor

@erudonja1 Robolectric claims that they've fixed the classloader issue that broke Powermock in your case in 3.3.1

see robolectric/robolectric#2944

@Zhuinden
Copy link
Contributor

Zhuinden commented Jun 16, 2017

Powermock 1.7.0 was released today (2017-06-16) with support for Mockito 2.x

See https://github.com/powermock/powermock/releases/tag/powermock-1.7.0

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 16, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests