Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Mockito to mock a local variable of a method

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?

like image 260
user657592 Avatar asked Apr 23 '14 06:04

user657592


People also ask

Can I mock a local variable?

No. You need a way to inject the mock. A local variable cannot be injected.

Can you mock a method?

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.

Can we mock public methods using Mockito?

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.

Can we mock private methods using Mockito?

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.


2 Answers

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 } 
like image 200
Mureinik Avatar answered Sep 19 '22 01:09

Mureinik


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.

like image 37
JB Nizet Avatar answered Sep 22 '22 01:09

JB Nizet