模拟一个类的静态函数

时间:2016-02-13 17:39:42

标签: java unit-testing

我正在实现一个类X,它有一个方法xyz(),它使用类A的静态方法abc()。这个静态方法abc()接受同一个类的另一个静态方法的返回值,它接受2个参数。一个是HTTPServletRequest对象,另一个是一个枚举的值。我想测试我的类X的方法xyz()的功能,为此我想到使用PowerMockRunner来模拟类A的xyz()方法。但是我在这里面临问题而不能这样做。 ''除了'子句不起作用,因此它没有返回值,我希望它返回正常测试继续。请指教。

@RunWith(PowerMockRunner.class)
@PrepareForTest(A.class)
public class DataProviderIntegrationTest {
@Mock
 private HttpServletRequest request;

 @TestSubject
 X x= new X();

 @Test
 public void testXyz() throws Exception {

 long customerId = 1;
 expect(A.abc(A.pqr(request, B.CUSTOMER_ID.getAttributeValue()))).andReturn(customerId);
 replayAll();
 Output output = x.xyz();

 Assert.assertNotNull(output);
 }
}

1 个答案:

答案 0 :(得分:1)

虽然你在询问如何模拟静态方法,但我会给你一个真实问题的答案。我想,你实际上是XY problem

因此,在测试您的某个方法时,您有机会大大改进您的测试代码。你显然已经意识到静态方法可能是测试的痛苦。怎么办?

简单回答:通过界面表达所需的功能!

我将给出一个Java运行时库中的一些静态方法的示例。您可以轻松地将机制传输到您的代码。让我们使用静态的Math.random()方法。应测试的方法:

final class MyClass {
    double myMethod(double multiplier) {
        double result = Math.random() * multiplier;
        return result;
    }
}

对随机功能的调用实际上是此代码所属类的依赖项。所以我们首先创建一个包含这个功能的接口:

interface Randomizer {
    double random();
}

此外,我们为它创建了第一个实现:

final class DefaultRandomizer implements Randomizer {
    @Override
    public double random() {
        return Math.random();
    }
}

现在我们可以将类重写为:

final class MyClass {
    private final Randomizer randomizer;

    MyClass() {
        this(new DefaultRandomizer());
    }

    MyClass(Randomizer randomizer) {
        this.randomizer = Objects.requireNonNull(randomizer);
    }

    double myMethod(double multiplier) {
        double result = randomizer.random() * multiplier;
        return result;
    }
}

正如您所见,该类的对象现在通过向它们提供所需的Randomizer来实例化。无参数构造函数是提供默认构造函数的简单方法。它可以省略,但是代码的其他部分也必须改变。

现在测试变得非常简单。您只需创建一个用于实例化该类的接口Randomizer的测试实现。这样做可以让您完全控制测试方法的各个方面。

这种测试的一个例子:

public final class MyClassTest {

    @Test
    public void zeroRandomShouldReturnZeroForPositiveMultiplier() {
        Randomizer zeroRandomizer = new Randomizer() {
            @Override
            public double random() {
                return 0.0;
            }
        };
        MyClass testObject = new MyClass(zeroRandomizer);
        double multiplier = 42.0;
        assertThat(testObject.myMethod(multiplier), is(0.0));
    }

}

使用Mockito可以轻松完成测试实现的创建(我也是出于这些目的)。但是......这个场景不需要模拟框架。事实上,这不是 mocking ,它是简单的 stubbing