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