I have a class A
that needs to the tested. The following is the definition of A
:
public class A { public void methodOne(int argument) { //some operations methodTwo(int argument); //some operations } private void methodTwo(int argument) { DateTime dateTime = new DateTime(); //use dateTime to perform some operations } }
And based on the dateTime
value some data is to be manipulated, retrieved from the database. For this database, the values are persisted via a JSON file.
This complicates things. What I need is to set the dateTime
to some specific date while it is being tested. Is there a way I can mock a local variable's value using mockito?
No. You need a way to inject the mock. A local variable cannot be injected.
Mocking is done when you invoke methods of a class that has external communication like database calls or rest calls. Through mocking you can explicitly define the return value of methods without actually executing the steps of the method.
With Mockito, you create a mock, tell Mockito what to do when specific methods are called on it, and then use the mock instance in your test instead of the real thing. After the test, you can query the mock to see what specific methods were called or check the side effects in the form of changed state.
For Mockito, there is no direct support to mock private and static methods. In order to test private methods, you will need to refactor the code to change the access to protected (or package) and you will have to avoid static/final methods.
You cannot mock a local variable. What you could do, however, is extract its creation to a protected
method and spy
it:
public class A { public void methodOne(int argument) { //some operations methodTwo(int argument); //some operations } private void methodTwo(int argument) { DateTime dateTime = createDateTime(); //use dateTime to perform some operations } protected DateTime createDateTime() { return new DateTime(); } } public class ATest { @Test public void testMethodOne() { DateTime dt = new DateTime (/* some known parameters... */); A a = Mockito.spy(new A()); doReturn(dt).when(a).createDateTime(); int arg = 0; // Or some meaningful value... a.methodOne(arg); // assert the result }
The best way to deal with such a problem is to use an injected Clock
service, used to get new instances of DateTime. That way, your test can inject a mock Clock, which returns a specific DateTime instead of the current time.
Note that the new Java 8 time API defines such a Clock class, specifically for that purpose.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With