Powermock:如何在枚举常量中模拟方法

时间:2018-11-13 14:51:49

标签: java unit-testing mocking powermock powermockito

我有一个枚举类型,它用作实现公共接口的其他对象的工厂的集合。该代码的简化版本是:

interface Operation { 
    void execute();
}

enum Factory {
    TYPE1(Class1::new),
    TYPE2(Class2::new);

    private Supplier<Operation> constructor;

    Factory(Supplier<Operation> constructor) {
        this.constructor = constructor;
    }

    Operation build() {
        return constructor.get(); 
    }
}

客户端代码的简化版本如下:

class Client {
    private void run(EnumSet<Factory> required) {
        for (Factory x : required) {
            x.build().execute(); 
        }
    }

    // Some code that calls run() with the right EnumSet
}

这一切似乎都能按预期工作,因此我想编写一些单元测试。

测试Factory很容易,但是事实证明Client更加困难。问题是我不想开始调用Operation(它们需要做很多工作)。相反,我想让x.build()返回一个模拟对象。

我尝试使用PowerMocks whenNew来捕获Operation对象的创建,但这不起作用(我实际上没有任何“新”操作)。我也尝试过使用Powermock的“间谍”,但这失败了,因为枚举常量是真实的对象。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

两种解决方案:

  • 您坚持使用PowerMock(ito)。那么简单的问题是:您可能准备了错误的类进行测试。您必须对那些 constants 枚举感到脾气,它们是 inner 类。但是有可能,例如,请参见此answer
  • 您退后一步,改进生产代码,使其更易于测试。

例如这样的例子:

interface OperationProvider { 
    Operation build();
}

用法如下:

enum Factory implements OperationProvider {

现在您可以更改客户端代码了

OperationProvider ourProvider = ...
whatever.build();...

重点是:使用依赖项注入时,您只需传递一个模拟的 OperationProvider。这意味着您基本上可以完全避免使用枚举进行模拟的需要。您只需要确保在生产代码中例如在初始化ourProvider字段时显然传递了一个枚举常量。