简体   繁体   中英

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 - eg 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 (eg 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM