Unit testing 如何在静态方法中模拟对对象的静态方法调用?

Unit testing 如何在静态方法中模拟对对象的静态方法调用?,unit-testing,junit,static-methods,powermockito,static-class,Unit Testing,Junit,Static Methods,Powermockito,Static Class,我是Junit测试的新手,但我必须测试一些代码。我想现在我知道了它的基本原理,但我仍然遇到了一个问题,我在互联网上找不到任何东西: 下面是我要测试的类: public static void methodToTest(Label l2, Label l3, User u) { int first = MyDB.someMethod(u.anotherMethod()).size(); int second = MyDB.someOtherMethod(u).size();

我是Junit测试的新手,但我必须测试一些代码。我想现在我知道了它的基本原理,但我仍然遇到了一个问题,我在互联网上找不到任何东西:

下面是我要测试的类:

public static void methodToTest(Label l2, Label l3, User u) {


    int first = MyDB.someMethod(u.anotherMethod()).size();
    int second = MyDB.someOtherMethod(u).size();


    if (first == 1) {
        l2.setCaption("...");
    }

    ...
}
我不希望系统创建整数“first”和“second”。相反,我只希望它们是“1”,这样我就可以测试最后几行代码是否正常工作

MyDB是一个带有静态方法(someMethod()和someOtherMethod()的公共类

我想测试methodToTest的方法。我尝试用parms调用这个方法,最后将修改后的参数与预期的参数进行比较

我使用Mockito和PowerMockito

这是我的一次尝试:

@PrepareForTest({ClassToTest.class, MyDB.class })
@RunWith(PowerMockRunner.class)
public class Test extends PowerMockTestCase{
   PowerMockito.mockStatic(MyDB.class);
   PowerMockito.doReturn(1).when(MyDB.someMethod(u.anotherMethod()).size());
   PowerMockito.doReturn(1).when(MyDB.someOtherMethod(u).size());
   ClassToTest.methodToTest(l1, l2, u);
   assertTrue(l1.equals(l3) && l2.equals(l4));
}
我得到的例外是: '传递给when()的参数不是模拟参数!'

我希望任何人都能帮助我。我花了这么多时间来解决这个问题,但没有成功


谢谢你

正如我在评论中提到的,您已经发现静态方法是测试的障碍。因此,我建议您避免使用静态方法。让我们看看在您的示例中会是什么样子:

您需要测试一些代码

public class ProductionClass {
  public static void methodToTest(Label l2, Label l3, User u) {
    int first = MyDB.someMethod(u.anotherMethod()).size();
    int second = MyDB.someOtherMethod(u).size();

    if (first == 1) {
        l2.setCaption("...");
    }

    ...
  }
}
第一件事。将生产类的静态方法作为实例方法:

public class ProductionClass {
  public void methodToTest(Label l2, Label l3, User u) {  // removed "static"
    int first = MyDB.someMethod(u.anotherMethod()).size();
    int second = MyDB.someOtherMethod(u).size();

    if (first == 1) {
        l2.setCaption("...");
    }

    ...
  }
}
好的,所以在MyDB上仍然有与静态方法的耦合。去掉一个静态方法只会使生产类更易于测试。下面是如何..您可以像这样进行两次提取方法重构:

public class ProductionClass {
  public void methodToTest(Label l2, Label l3, User u) {
    int first = getFirst();
    int second = getSecond();

    if (first == 1) {
        l2.setCaption("...");
    }

    ...
  }

  int getFirst() {
    return MyDB.someMethod(u.anotherMethod()).size();
  }

  int getSecond() {
    return MyDB.someOtherMethod(u).size();
  }
}
现在,您可以轻松地对该生产类进行子类化,并覆盖(或部分模拟,如果您愿意的话)您想要使用的方法

public class TestableProductionClass extends ProductionClass {
  @Override
  int getFirst() {
    return 1;
  }

  @Override
  int getSecond() {
    return 1;
  }
}

不会让事情变得更难,引入PowerMock会增加我不愿意处理的复杂性。YMMV。祝你好运

当然,您可以模拟静态方法,但是摆脱它们以及它们带来的不便的隧道依赖不是更好吗?这就是我的建议:避免使用静态方法。如果您正在使用其他人的代码,并且在进行测试之前不会对其进行重构,那么您可能会发现像JMockit这样的工具比Mockito和PowerMockito更容易使用。