Using Mockito to mock a local variable of a method

103,676

Solution 1

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
}

Solution 2

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.

Share:
103,676
user657592
Author by

user657592

Updated on July 09, 2022

Comments

  • user657592
    user657592 almost 2 years

    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?

  • user657592
    user657592 about 10 years
    I don't wish to write a protected createDateTime() method. Is there no other way to go about it?
  • user657592
    user657592 about 10 years
    This requires a jdk1.8, right? I am currently on 1.7 and am not planning to upgrade anytime soon.
  • JB Nizet
    JB Nizet about 10 years
    No. You just need to define your own Clock class or interface, and call clock.newDateTime() instead of new DateTime() to get the current time.
  • Alex
    Alex over 6 years
    Actually you have to use Mockito.doReturn(dt).when(a).createDateTime() Please see stackoverflow.com/questions/11620103/…
  • Mureinik
    Mureinik over 6 years
    This is of course correct @Alex, thanks for noticing! Edited and fixed.
  • WesternGun
    WesternGun almost 5 years
    Cannot spy() a class when it does not have default constructor. Want to avoid it.
  • Mureinik
    Mureinik almost 5 years
    @WesternGun in the above snippet, you supply an instance of A you want to spy. It has nothing to do with a default constructor - you can construct this instance however you wish.
  • WesternGun
    WesternGun almost 5 years
    OK I meant @Spy of mockito.