Randomness Mocking With JMockit
01 Apr 2016If you had already tried to cover same bigger part of your code with JUnit tests, you have probably encountered it. With JUnit we can run tested code with predefined input and check output of it. But what if this code use, on background without control of calling code, same objects, which provide non-deterministic or changing output, like random numbers generator or real time source? How can we cover such code with tests? This can be solved using mocking.
Mocking is creating fake objects, which will act role of the object, which we want to get out of the test. Such a fake objects will be spoofed on place it and tested code will use within our test fake object instead of unpleasant real objects.
In this tutorial I will show example, how to mock most problematic classes of JDK.
At first we need to add JMockit library into us project. If you use maven, it is simple - just add following dependency:
As the second step we need to ensure that the test will be started with JMockit:
Before mocking Random
itself, lets try it with much simpler, but closely related, subject - mocking of system time.
We will prepare mock of System
class - here we would like to ensure constant “current” time:
Just note - for mocking of Random
/SecureRandom
is not mocking of system time required. But it is not only example too - if you want to mock Random
, it is likely you will want to mock the system time too.
Similar mock as for the System
class we will prepare to mock the Random
class. But it can cause problems in same algorithms (like key generation), where returning of constant “random” values everytime would cause getting stuck in infinite loop. We will keep pseudorandomicity of the Random
output, but we will ensure that it will return the same pseudorandom sequence on every test run. Following code will replace seed (from which the pseudorandom numbers are generated) on every new instance of Random
creation:
We will keep all methods of Random
untouched - they generate random values based on the seed, which is what we want.
If we would like to mock the SecureRandom
too, we just replace it with non-secure Random
, which is already mocked:
Other methods of SecureRandom
use this method to obtain the random values, so we can keep them as they are.
To start use defined mock classes we have to create new instances of them. In JUnit we can use method with @BeforeClass
annotation to ensure start using them before every test run:
The tests alone will look as usual, just mocked classes will provide mocked output:
The complete example of above you can found in gist.