Static method call not being mocked on some threads using RxJava

2,990 views
Skip to first unread message

Radek Bartoň

unread,
May 12, 2017, 5:28:58 AM5/12/17
to PowerMock
Hello everyone.

I am trying to unit test some code that is using RxJava for asynchronicity and parallelism and that is using Realm database to fetch data. Since Realm cannot be used in tests, it needs to be mocked:

  mockStatic(Realm.class);
Realm mockRealm = mock(Realm.class);
when(Realm.getDefaultInstance())
.thenReturn(mockRealm);

This mocking of Realm.getDefaultInstance() works completely fine with simple RxJava observable chains/trees even when some of them are executed in different threads and are calling the Realm.getDefaultInstance() method. But when the test (chain/tree of observables) is quite complex it happens that in some threads the call of Realm.getDefaultInstance() executes the real method which leads to unit test stuck. Unfortunatelly I haven't found the only and necessary conditions when that happens so I cannot present you some short code which reproduces the issue by itself.

Is that some known issue? Do you have any idea where to look for an explanation of this issue?

Radek Bartoň

unread,
May 12, 2017, 7:12:37 AM5/12/17
to PowerMock
Update: It seems that mocking works fine. Only the debugger shows me the real code but program control is actually in PowerMock code. After stepping inside serveral times, I got to MockitoMethodInvocationControl class to its getVerificationMode() method where the test stucks at line:

MockingProgress e = (MockingProgress)Whitebox.invokeMethod(ThreadSafeMockingProgress.class, "threadSafely", new Object[0]);

Forgot to mention that I'm using PowerMock 1.6.4 because of Robolectric.

WodenCafe

unread,
May 12, 2017, 10:04:38 AM5/12/17
to PowerMock
Have you tried @PrepareForTest(Realm.class) ?

Radek Bartoň

unread,
May 12, 2017, 10:18:27 AM5/12/17
to PowerMock
Of course, otherwise the mocking would not work in any thread.

On Friday, 12 May 2017 16:04:38 UTC+2, WodenCafe wrote:
Have you tried @PrepareForTest(Realm.class) ?

WodenCafe

unread,
May 12, 2017, 10:27:38 AM5/12/17
to PowerMock
What happens if you use @PrepareEverythingForTest?

Zagretdinov Arthur

unread,
May 14, 2017, 4:14:59 PM5/14/17
to powe...@googlegroups.com

Hi Radek,

You’re moving in right way. PowerMock heavy relies on Mockito and how it works. PowerMock just provides proxy for static methods and register  a fake mock object. So in case if a really method is called instead mocked then it means that Mockito cannot match current call to mocked. I found the following in Mockito documentation: 

Is Mockito thread-safe?

For healthy scenarios Mockito plays nicely with threads. For instance, you can run tests in parallel to speed up the build. Also, you can let multiple threads call methods on a shared mock to test in concurrent conditions. Check out a timeout() feature for testing concurrency.

However Mockito is only thread-safe in healthy tests, that is tests without multiple threads stubbing/verifying a shared mock. Stubbing or verification of a shared mock from different threads is NOT the proper way of testing because it will always lead to intermittent behavior. In general, mutable state + assertions in multi-threaded environment lead to random results. If you do stub/verify a shared mock across threads you will face occasional exceptions like: WrongTypeOfReturnValue, etc.



I’m afraid that it could really hard to find case to reproduce issue. Only code analyst could help. 

--
You received this message because you are subscribed to the Google Groups "PowerMock" group.
To unsubscribe from this group and stop receiving emails from it, send an email to powermock+...@googlegroups.com.
To post to this group, send email to powe...@googlegroups.com.
Visit this group at https://groups.google.com/group/powermock.
For more options, visit https://groups.google.com/d/optout.

Radek Bartoň

unread,
May 15, 2017, 4:33:16 AM5/15/17
to PowerMock
Hello Artur,

thank you for the explanation. I am not doing any verification on the mocks. I am stubbing the Ream instance only once in @Before method for all tests on main thread. Then the stubbed methods are only called from different threads. Is that the same concrurrency problem? 

Radek Bartoň

unread,
May 15, 2017, 4:44:36 AM5/15/17
to PowerMock
Hello Cafe.

That cannot be used be cause of "java.lang.IllegalArgumentException: Cannot subclass final class" error in my tests.

But anyway I am sorry that I missleaded you with the first wording of my question. Please see my update on the matter that the problem is not actually that the mock would not mocked, because I was confused by the debugger showing me a real code instead of PowerMock code when I stepped in, but the problem is that the test is stuck on line 

MockingProgress e = (MockingProgress)Whitebox.invokeMethod(ThreadSafeMockingProgress.class, "threadSafely", new Object[0]);

in MockitoMethodInvocationControl class. By the stuck I mean that the test is waiting infinitely on that line or at least I cannot step into or step over to another line of PowerMock/Mockito code.

Zagretdinov Arthur

unread,
May 15, 2017, 8:01:27 AM5/15/17
to powe...@googlegroups.com

It could be same or another concurrency problem. I've seen that you debug code and test execution stucks on invocation of thread safe mocking process. Unfortunately, I cannot check it now, but as I remember Mockito use thread local to store InvocationProcess without synchronization. Have you tried to break point to the `ThreadSafeMockingProgress.threadSafely`?

By the way, you mentioned that use 1.6.4. Is it some well known issue with latest PowerMock? Maybe you could trie Mockito 2 and latest PowerMock where such dirty hack is replaced by using public API? 

Radek Bartoň

unread,
May 15, 2017, 8:53:34 AM5/15/17
to PowerMock
Thank you for an idea where to look for. I tried to put breakpoint at the first line of ThreadSafeMockingProgress.threadSafely() but the program control does not get there. It event does not get to the first line of Whitebox.invokeMethod().

I cannot use newer version of PowerMock than 1.6.4 because my tests heavily depends on Robolectric. I will try to create parallel project with a similar unit test where all Andorid classes are mocked without Robolectric and with the latest PowerMock version but that will take some time.

Elyashiv Lavi

unread,
Jun 19, 2018, 9:16:20 AM6/19/18
to PowerMock
I'm also facing the same issue...

My tests are stuck on this scenario

Did you find a way to overcome this issue?

בתאריך יום שני, 15 במאי 2017 בשעה 15:53:34 UTC+3, מאת Radek Bartoň:

Nam Tongdosa

unread,
Sep 23, 2021, 6:05:47 AM9/23/21
to PowerMock
Reply all
Reply to author
Forward
0 new messages