Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SecurityProvider in Mockito Tests when run alongside Robolectric

We haven an Android project where we use MockitoTestRunner and RobolectricTestRunner for different kinds of tests.

I have written a set of unit test that are concerned with SSL, thus loading certs/keystores/truststores, etc. For this I used the MockitoJUnitRunner and added the Bouncycastle provider programmatically as such:

Security.insertProviderAt(new BouncyCastleProvider(), 1);

Now, these tests run perfectly fine when run on their own - e.g. when I directly run single methods from the test classes, or run these classes from the Project tree menu, they work just fine.

But when I run said tests along side ANY test which uses the RobolectricTestRunner (such as if I just run all the tests in my project together before committing), I get the following exception:

java.io.IOException: error constructing MAC:
java.lang.SecurityException: JCE cannot authenticate the provider BC

I'm baffled. How will the testrunner used in one test class affect the run of other classes, especially if we use a different test runner?


Additional info:

  • The exception only occurs once I actually try do do something with the BC provider (e.g. the first time the test tries to load a PKCS12 certificate) - the insertProviderAt(...) call itself seems to pass fine...
  • Also when I print out the list of providers for each test run, I see that Robolectric already has a BC provider in there, but is still failing when I try to use it.
  • Also if I don't add the BC provider, the tests still fail with the same error when run in a test suite alongside Robolectric tests. When run alone they fail with java.security.NoSuchProviderException: no such provider: BC, as we're specifying the provider explicitly.
like image 245
fgysin Avatar asked Apr 06 '17 14:04

fgysin


People also ask

What is the difference between Mockito and Robolectric?

This is in contrast to using pure Mockito, which often ends up with tests that are the reverse of the logic you are attempting to test. Robolectric works by emulating the native calls the SDK would make on Dalvik, but on the JVM, so it can run much, much faster. This makes full unit testing and TDD possible.

Can we use Mockito without JUnit?

Mockito is a mocking framework. It is a Java-based library used to create simple and basic test APIs for performing unit testing of Java applications. It can also be used with other frameworks such as JUnit and TestNG.

Is Mockito part of spring boot test?

Spring Boot provides a number of useful tools for testing your application. The spring-boot-starter-test POM provides Spring Test, JUnit, Hamcrest and Mockito dependencies. There are also useful test utilities in the core spring-boot module under the org.


1 Answers

Seems like Robolectric is using its own classloader (that favors its replacements on the Android API), which could be in conflicts with the regular classloader of Mockito.

So for using at the same time the Robolectric and mockito, you may do the following:

  1. Make use of the Robolectric runner. Robolectric uses its own classloader that favors its replacements for the Android API, so it really does need to handle classloading on its own. There's no other way to use Robolecric.

  2. Replace the @RunWith(MockitoJUnitRunner.class) with these alternative methods covering the behaviour of MockitoJUnitRunner:

    @Before public void setUpMockito() {
       MockitoAnnotations.initMocks(this);
     }
    
     @After public void tearDownMockito() {
       Mockito.validateMockitoUsage();
     }
    

Maybe it could be a workaround for using the Robolectric classloader and Mockito at the same time.

like image 67
Damian229 Avatar answered Sep 19 '22 22:09

Damian229