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

时间:2019-10-21 20:27:38

标签: java unit-testing enums mockito

我有两个枚举:

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

我已经通过使用Whitebox进行模拟为Y编写了一个单元测试类。但是,在为X编写单元测试用例时,需要获得以下异常:

我收到以下错误消息:

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

这是单元测试用例:

public class XTest {
    @Mock private Y yMock;

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

我知道这个问题是因为我试图模拟一个枚举,它是一种原始类型。我想找到解决方法。

1 个答案:

答案 0 :(得分:1)

以下是Mockito文档中的内容:

  

39。模拟最终类型,枚举和最终方法(自2.1.0开始)

     

Mockito现在提供了一个孵化,可选的模拟最终课程支持   和方法。这是一个了不起的改进,证明了   Mockito对改善测试体验的永恒追求。我们的   我们的目标是使Mockito与最终的类和方法“兼容”。   以前,它们被认为是不可模仿的,从而阻止了用户   嘲笑。我们已经开始讨论如何制作此功能   默认情况下启用。目前,该功能仍是可选功能,因为我们   等待社区的更多反馈。

     

此功能默认情况下处于关闭状态,因为它基于   完全不同的模拟机制,需要更多反馈   来自社区。

但是,我宁愿建议用单例类中的静态成员单例替换枚举单例,因为如本测试用例所示,它通常被认为更具可读性,同等的线程安全性和可配置性。

类似这样的东西:

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() {  // ...
            }
        }

我还要补充一点,我不喜欢在测试期间使用Whitebox。我相信测试可以做的任何事情,我的代码都应该可以做,因为测试是模块的第一个真正的客户,并且可以指示将来的客户可能想要做什么。例如,就像测试想用模拟Y替换Y一样,将来有人可能会想将X与其他生产Y一起使用。

我将更改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() { // ...
            }
        }

我会牺牲一些安全性(例如X.INSTANCE.setY(null);的可能性)以实现可配置性和简洁的代码。