简体   繁体   English

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

[英]Powermock: How to mock a method in an enumeration constant

I have an enumeration type which I used as a collection of factories for other objects that implement a common interface.我有一个枚举类型,我将其用作实现公共接口的其他对象的工厂集合。 A simplified version of the code is:代码的简化版本是:

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(); 
    }
}

A simplified version of the client code looks like:客户端代码的简化版本如下所示:

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

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

This all appears to work as expected, so I want to write some Unit tests.这一切似乎都按预期工作,所以我想编写一些单元测试。

Testing the Factory is easy, but the Client is proving more difficult.测试Factory很容易,但事实证明Client更困难。 The problem is that I don't want to start calling the Operation (they do a lot of work).问题是我不想开始调用Operation (他们做了很多工作)。 Instead I'd like to get x.build() return a mock object.相反,我想让x.build()返回一个模拟对象。

I've tried using PowerMocks whenNew to trap the creation of the Operation objects, but this doesn't work (I don't actually have any 'new' operations).我已经尝试使用 PowerMocks whenNew来捕获Operation对象的创建,但这不起作用(我实际上没有任何“新”操作)。 I've also tried to use a Powermock 'spy', but this fails because the enumeration constants are real objects.我也尝试过使用 Powermock 'spy',但是这失败了,因为枚举常量是真实的对象。

Any ideas?有任何想法吗?

Two solutions:两种解决方案:

  • you insist on using PowerMock(ito).你坚持使用 PowerMock(ito)。 Then the simple issue is: you are probably preparing the wrong class for test.那么简单的问题是:您可能正在为测试准备错误的课程。 You have to temper with those enum constants , and they are inner classes.你必须调整那些枚举常量,它们是内部类。 But it is possible, see this answer for example.但这是可能的,例如,请参阅此答案
  • you step back, and improve your production code, to make it easier to test.你退后一步,改进你的生产代码,使其更容易测试。

For example like this:例如像这样:

interface OperationProvider { 
    Operation build();
}

to be used like:像这样使用:

enum Factory implements OperationProvider {

And now you can change your client code to do现在你可以改变你的客户端代码来做

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

The point is: when using dependency injection, you simply pass a mocked OperationProvider.关键是:在使用依赖注入时,您只需传递一个模拟的OperationProvider。 This means that you can basically sidestep the need to mock with your enum completely.这意味着您基本上可以完全避免使用枚举进行模拟的需要。 You just have to make sure that within your production code, you obviously pass one of the enum constants when initializing that ourProvider field for example.例如,您只需要确保在您的生产代码中,您显然在初始化ourProvider字段时传递了枚举常量之一。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM