简体   繁体   English

如何在 Java 中的另一个枚举中模拟一个枚举?

[英]How to mock an enum inside another enum in Java?

I have two enums:我有两个枚举:

public enum X {
    INSTANCE;
    private final Y y = Y.INSTANCE;

    public boolean isfunc() {
        return y.someMethod();
    }
}
public enum Y {
    INSTANCE;

    public boolean someMethod() {
        return true;
    }
}

I have written a unit test class for Y by mocking using Whitebox.我已经使用 Whitebox 为Y by mocking 编写了一个单元测试 class。 However, I need to get the following exception while writing the unit test case for X :但是,在为X编写单元测试用例时,我需要得到以下异常:

I am getting the following error message:我收到以下错误消息:

Cannot mock/spy class
Mockito cannot mock/spy following:
  - final classes
  - anonymous classes
  - primitive types

Here are the unit test cases:以下是单元测试用例:

public class XTest {
    @Mock private Y yMock;

    @Before
    public void setUp() throws Exception {
        Whitebox.setInternalState(Y.INSTANCE, "y", yMock);
    }

I understand that the issue is because I am trying to mock an enum which is a primitive type.我知道这个问题是因为我试图模拟一个原始类型的枚举。 I want to find a way around this.我想找到解决这个问题的方法。

Here's a bit from Mockito's Documentation:以下是 Mockito 文档中的一些内容:

39. Mocking final types, enums and final methods (Since 2.1.0) 39. Mocking 最终类型、枚举和最终方法(自 2.1.0 起)

Mockito now offers an Incubating, optional support for mocking final classes and methods. Mockito 现在提供对 mocking 最终类和方法的孵化可选支持。 This is a fantastic improvement that demonstrates Mockito's everlasting quest for improving testing experience.这是一个了不起的改进,展示了 Mockito 对改善测试体验的不懈追求。 Our ambition is that Mockito "just works" with final classes and methods.我们的目标是 Mockito 与 final 类和方法“正常工作”。 Previously they were considered unmockable, preventing the user from mocking.以前它们被认为是不可修改的,从而阻止用户使用 mocking。 We already started discussing how to make this feature enabled by default.我们已经开始讨论如何默认启用此功能。 Currently, the feature is still optional as we wait for more feedback from the community.目前,该功能仍然是可选的,因为我们等待来自社区的更多反馈。

This feature is turned off by default because it is based on completely different mocking mechanism that requires more feedback from the community.此功能默认关闭,因为它基于完全不同的 mocking 机制,需要社区更多反馈。

However, I would rather recommend replacing the enum Singleton with a static member singleton in a singleton class, as it is often considered more readable, equally thread safe, and more configurable, as this test case shows. However, I would rather recommend replacing the enum Singleton with a static member singleton in a singleton class, as it is often considered more readable, equally thread safe, and more configurable, as this test case shows.

Something like this:像这样的东西:

public class Y {
    private Y() {}
    private final static Y y = new Y();
    public static Y getInstance() {
        return y;
    }

    public boolean someMethod() {
        return true;
    }
}

        enum X {
            INSTANCE;
            private final Y y = Y.getInstance();

            public boolean isfunc() {
                return y.someMethod();
            }
        }

        public class XTest {
            @Mock private Y yMock;

            @Before
            public void setUp() throws Exception {
                Whitebox.setInternalState(X.INSTANCE, "y", yMock);
            }

            @Test
            void test() {  // ...
            }
        }

I would add further, that I dislike using Whitebox during tests.我还要补充一点,我不喜欢在测试期间使用 Whitebox。 I believe that anything the test can do, my code should be able to do, as the test is the first real client of my module, and an indicator of what future clients might want to do.我相信测试可以做的任何事情,我的代码都应该可以做,因为测试是我模块的第一个真正的客户端,并且是未来客户可能想要做什么的指标。 For example, just like the test would like to replace Y with a mock Y, in the future someone might like to use X with a different production Y.例如,就像测试想用模拟 Y 替换 Y 一样,将来有人可能想将 X 与不同的生产 Y 一起使用。

I would change Y to use an interface, and remove the final of the y variable in X, in order to make it settable, as follows:我会将 Y 更改为使用接口,并删除 X 中 y 变量的最后一个,以使其可设置,如下所示:

interface IY
{
    public boolean someMethod();
}

public class Y implements IY {
    private Y() {}
    private final static IY y = new Y();
    public static IY getInstance() {
        return y;
    }

    public boolean someMethod() {
        return true;
    }
}    

        enum X {
            INSTANCE;
            private IY y = Y.getInstance();
            public void setY(IY y)
            {
                this.y = y;
            }

            public boolean isfunc() {
                return y.someMethod();
            }
        }

        public class XTest {
            @Mock private Y yMock;

            @Before
            public void setUp() throws Exception {
                X.INSTANCE.setY(yMock);
            }

            @Test
            void test() { // ...
            }
        }

I would sacrifice some safety ( for example the possiblity of X.INSTANCE.setY(null); ) for configurability and clean code.为了可配置性和干净的代码,我会牺牲一些安全性(例如 X.INSTANCE.setY(null); 的可能性)。

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

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