如何模拟ENUM类中的方法?

时间:2014-01-18 09:59:36

标签: java junit enums jmockit

我正在为下面的ENUm课程编写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();
    }
}

5 个答案:

答案 0 :(得分:1)

有可能,但不推荐,重构代码会更好。

Mockito / PowerMock的工作示例

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

    @Mock
    InetAddress inetAddress;

    @Test
    public void shouldReturnDatacenter() throws UnknownHostException {
        //given
        mockStatic(InetAddress.class);
        given(inetAddress.getCanonicalHostName()).willReturn("foo");
        given(InetAddress.getLocalHost()).willReturn(inetAddress);

        //when
        String datacenter = DatacenterEnum.getDatacenter();

        //then
        assertThat(datacenter).isEqualTo("foo");
    }
}

依赖关系

  • org.powermock:powermock模块-junit4:1.5.2
  • org.powermock:powermock-API的Mockito:1.5.2
  • org.assertj:assertj-core:1.5.0
  • 的junit:junit的:4.11

答案 1 :(得分:1)

您可以创建数据中心界面并让枚举实现该界面。这会使模拟更容易。

最重要的是,我不会在Enum中放置配置信息。如果您必须添加其他数据中心(或数据中心更改的配置),则必须重新编译代码。考虑将配置放在普通的类读取中,例如java属性文件或XML文件。 (此功能可能已在您的框架中实现。)

如果无法做到这一点,您可以使用“黑暗反射”法术将Enum中的字段更改为所需的值。

答案 2 :(得分:1)

使用JMockit很容易:

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

    String datacenter = DatacenterEnum.getDatacenter();

    assertEquals("foo", datacenter);
}

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

答案 3 :(得分:0)

这是你可以用Mockito / Powermock做到这一点的方法。你需要Powermock,因为Mockito无法模拟静态mehtods:

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

<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 :(得分:0)

我可能是老上学,但我确实重构了测试中的代码而不是使用classloader hacks。类似的东西:

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


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

    public static String getHostName() {
        return hostName;
    }
}

并在测试代码中,在运行测试之前:

DataCenterEnum.hostName = "foo";