使用Mockito模拟方法的局部变量

use*_*592 29 java mocking functional-testing mockito

我有一个A需要经过测试的课程.以下是定义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
    }
}
Run Code Online (Sandbox Code Playgroud)

并且基于该dateTime值,一些数据将被操纵,从数据库中检索.对于此数据库,值通过JSON文件保留.

这使事情复杂化.我需要的dateTime是在测试时将其设置为某个特定日期.有没有办法可以使用mockito模拟局部变量的值?

Mur*_*nik 32

你不能模拟局部变量.但是,你可以做的是将它的创建提取到一个protected方法,spy它:

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
}
Run Code Online (Sandbox Code Playgroud)

  • 我不希望编写受保护的createDateTime()方法.没有别的办法吗? (11认同)
  • 实际上你必须使用 Mockito.doReturn(dt).when(a).createDateTime() 请参阅 /sf/ask/813407241/原始方法 (3认同)
  • 这当然是正确的@Alex,感谢您的注意!编辑和修复。 (2认同)
  • 如果没有默认构造函数,则不能`spy()` 类。想避免。 (2认同)

JB *_*zet 5

处理此类问题的最佳方法是使用注入Clock服务,用于获取 DateTime 的新实例。这样,您的测试可以注入一个模拟时钟,它返回特定的日期时间而不是当前时间。

请注意,新的 Java 8 时间 API 专门为此目的定义了这样一个Clock 类。

  • 不需要。您只需要定义自己的 Clock 类或接口,然后调用“clock.newDateTime()”而不是“new DateTime()”即可获取当前时间。 (2认同)