使用Mockito,如何在没有该类实例的情况下模拟实例方法的返回值?

时间:2016-03-19 01:16:04

标签: java android unit-testing junit mockito

我有一个名为MyClass的班级。我在该课程中有一个方法,public int getSpacing()

我正在测试来自不同类的方法。 public static ArrayList<SpecialObject> getSpecialObjects()

getSpecialObjects()getSpacing()的实例上调用MyClass。当我使用Mockito运行测试时,我希望此方法始终返回0。我怎样才能做到这一点?在模拟方法之前,我发现的所有示例都需要一个对象的特定实例。

这就是我所知道的。

MyClass myInstance = new MyClass();        
Mockito.when(myInstance.getSpacing()).thenReturn(0);

但是,我想覆盖getSpacing()的所有实例的MyClass行为,因为实例是在getSpecialObjects()中动态创建的。我怎么能这样做?

这就是我想说的,但不知道如何。

Mockito.when((Any instance of MyClass).getSpacing()).thenReturn(0);

2 个答案:

答案 0 :(得分:1)

您可以使用powermock模拟MyClass构造函数,如下所示:

MyClass myClassSpy = spy(new MyClass());
whenNew(MyClass.class).withAnyArguments().thenReturn(myclassSpy);

然后你可以使用间谍的常规覆盖从该方法返回任何你喜欢的东西。不要忘记PrepareForTest

MyClass

答案 1 :(得分:1)

你不能像你所描述的那样纯粹在Mockito这样做。 Mockito不控制MyClass类型的所有对象,而是使得创建和实例化它可以控制的代理子类非常容易。这就是为什么Mockito依赖于非最终的类和方法,以及为什么你不能使用Mockito来影响所有实例的行为。

另请参阅: How to use Mockito when we cannot pass a mock object to an instance of a class

一种解决方法是切换库:As Slava describes,您可以使用PowerMock,它具有修改字节码的自定义类加载器,其中包括替换对new MyClass()构造函数的调用,以便它们可以返回您的模拟。

作为替代方案,您可以重新构建类以使其更容易测试。您可以完全构造用于依赖注入的类并注入Provider<MyClass>,但是有一个更本地化的解决方案具有大部分好处:

public class ClassThatConsumesMyClass {
  /** Visible for testing. Override to customize MyClass instances. */
  MyClass createMyClass() {
    return new MyClass();
  }

  public ReturnValue getSpecialObjects(int n) {
    for (int i = 0; i < n; i++) {
      // Instead of calling "new MyClass()", call your method.
      MyClass myClassInstance = createMyClass();
      // ...
    }
    // ...
  }
}

public class TestForClassThatConsumesMyClass {
  ClassThatConsumesMyClass consumer;

  @Before public void createMyClass() {
    consumer = new ClassThatConsumesMyClass() {
      @Override MyClass createMyClass() {
        MyClass myInstance = Mockito.mock(MyClass.class);
        Mockito.when(myInstance.getSpacing()).thenReturn(0);
        return myInstance;
      }
    }
  }

  // Test as usual, now that you've mocked every newly-created
  // instance of MyClass in your consumer.
}