Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/363.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何模拟枚举类中的方法?_Java_Junit_Enums_Jmockit - Fatal编程技术网

Java 如何模拟枚举类中的方法?

Java 如何模拟枚举类中的方法?,java,junit,enums,jmockit,Java,Junit,Enums,Jmockit,我正在为我下面的枚举类编写JUNIT测试用例。我下面的类只会给我当前运行代码的机器的主机名。在我编写JUNIT测试时,如何模拟下面的类,以便我可以随时更改getHostName()方法,以便无论何时调用getDatacenter(),它都可以通过模拟来返回我传递的任何主机名。我不想让它成为一个参数化的 我只想在模拟主机名时更改主机名,同时测试某些情况 public enum DatacenterEnum { DEV, DC1, DC2, DC3; public static

我正在为我下面的枚举类编写JUNIT测试用例。我下面的类只会给我当前运行代码的机器的主机名。在我编写JUNIT测试时,如何模拟下面的类,以便我可以随时更改
getHostName()
方法,以便无论何时调用
getDatacenter()
,它都可以通过模拟来返回我传递的任何主机名。我不想让它成为一个参数化的

我只想在模拟主机名时更改主机名,同时测试某些情况

public enum DatacenterEnum {
    DEV, DC1, DC2, DC3;


    public static String forCode(int code) {
    return (code >= 0 && code < values().length) ? values()[code].name() : null;
    }
    private static final String getHostName() {
        try {
            return InetAddress.getLocalHost().getCanonicalHostName().toLowerCase();
        } catch (UnknownHostException e) {
            s_logger.logError("error = ", e);
        }

        return null;
    }

    public static String getDatacenter() {
        return getHostName();
    }
}
公共枚举数据中心枚举{
DEV,DC1,DC2,DC3;
公共静态字符串forCode(整型代码){
返回(代码>=0&&code
这是可能的,但不建议这样做,最好重构代码

Mockito/PowerMock的工作示例 依赖关系
  • org.powermock:powermock-module-junit4:1.5.2
  • org.powermock:powermock api mockito:1.5.2
  • org.assertj:assertj核心:1.5.0
  • junit:junit:4.11

这是一种使用Mockito/Powermock的方法。您需要Powermock,因为Mockito无法模拟静态方法:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.junit.Assert.assertEquals;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;

@RunWith(PowerMockRunner.class)
@PrepareForTest({DatacenterEnum.class})
public class DatacenterEnumTest {

    @Test
    public void testGetDatacenter() {
        mockStatic(DatacenterEnum.class);
        when(DatacenterEnum.getDatacenter()).thenReturn("YourHostname");

        String datacenter = DatacenterEnum.getDatacenter();

        assertEquals("YourHostname", datacenter);
    }
}
Maven依赖项

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
    </dependency>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-api-mockito</artifactId>
        <version>1.5.2</version>
    </dependency>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4</artifactId>
        <version>1.5.2</version>
    </dependency>
</dependencies>

朱尼特
朱尼特
4.11
org.powermock
powermock api mockito
1.5.2
org.powermock
powermock-module-junit4
1.5.2

您可以创建一个数据中心接口,并让enum实现该接口。这将使嘲弄变得更容易

最重要的是,我不会首先将配置信息放在枚举中。如果必须添加其他数据中心(或数据中心的配置发生更改),则必须重新编译代码。考虑将配置放入正常类中,例如java属性文件或XML文件。(此函数可能已在您的框架中实现。)


如果不可能,您可以使用“变暗反射”魔术将枚举中的字段更改为所需的值。

使用JMockit很容易:

@Test
public void mockInetAddress(@Cascading final InetAddress inetAddress)
{
    new NonStrictExpectations() {{
        inetAddress.getCanonicalHostName(); result = "foo";
    }};

    String datacenter = DatacenterEnum.getDatacenter();

    assertEquals("foo", datacenter);
}

当然,您也可以在枚举中模拟
getHostName()
方法,但最好避免模拟
private
方法。

我可能是老派,但我真的会重构测试中的代码,而不是使用类加载器。比如:

public enum DatacenterEnum {
    DEV, DC1, DC2, DC3;


    static String hostName = InetAddress.getLocalHost().getCanonicalHostName().toLowerCase();

    public static String getHostName() {
        return hostName;
    }
}
在测试代码中,在运行测试之前:

DataCenterEnum.hostName = "foo";

这些方法必须在enum类中吗?枚举值和这些方法之间似乎没有任何引用。我已从代码中删除了这些信息。。有两种方法根据主机名相应地使用这些详细信息。。所以我最吸引人的地方是模仿getHostName方法,其他的代码都围绕着它转。导入看起来像什么?这只会部分起作用。
ClassLoader
的规则是在类的第一个引用上加载类,这需要静态初始值设定项。OP抛出了一个
UnknownHostException
,现在您已经将其移动到静态字段初始化,该初始化现在有机会将异常传播到
类加载器
。如果要引发某种已检查或未检查的异常,则将来分配给
hostName
将导致
NoClassDefFoundError
。将抛出异常的方法放入未经检查的初始值设定项中不是一个好主意。也许我过于热衷于删除catch块,但我无法想象DNS不知道本地主机名的情况?但是是的,如果你真的看到抛出这个异常,我会将查找移到一个专用的静态方法中,并添加一个catch块,这样类就可以正确初始化,测试代码就有机会重写主机名。抛出异常的是
InetAddress\getLocalHost()
函数本身,javadocs似乎只表明
本地主机名无法解析为地址。
但公平地说,我自己并没有想过为什么会发生这种情况。但在以下情况下确实会发生:。更重要的是,我只是抱着防御性编程的心态,以减少维护。
DataCenterEnum.hostName = "foo";