我正在为下面的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();
}
}
答案 0 :(得分:1)
有可能,但不推荐,重构代码会更好。
@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");
}
}
答案 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";