Java 如何模拟 ENUM 类中的方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21202576/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to mock a method in an ENUM class?
提问by
I am working on writing JUNIT test case for my below ENUm class. My below class will only give me the hostname for the current machine where I am running my code. While I am writing JUNIT test, how can I mock the below class, so that I can change getHostName()
method whenever I want to so that whenever I am calling getDatacenter()
, it can return me whatever hostname I am passing by mocking it. I don't want to make it as a parametrized.
我正在为我下面的 ENUM 类编写 JUNIT 测试用例。我下面的课程只会给我运行我的代码的当前机器的主机名。在编写 JUNIT 测试时,如何模拟下面的类,以便我可以随时更改getHostName()
方法,以便每当我调用 时getDatacenter()
,它都可以通过模拟它来返回我传递的任何主机名。我不想把它作为参数化。
I just want to test certain cases while changing the hostname while mocking it.
我只想在模拟主机名的同时测试某些情况。
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();
}
}
回答by MariuszS
It is possible, but this is not recommended, it would be better to refactor the code.
有可能,但不建议这样做,最好重构代码。
Working example with Mockito/PowerMock
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");
}
}
Dependencies
依赖关系
- org.powermock:powermock-module-junit4:1.5.2
- org.powermock:powermock-api-mockito:1.5.2
- org.assertj:assertj-core:1.5.0
- junit:junit:4.11
- org.powermock:powermock-module-junit4:1.5.2
- org.powermock:powermock-api-mockito:1.5.2
- org.assertj:assertj-core:1.5.0
- junit:junit:4.11
回答by Philipp Hofmann
This is a way you can do it with Mockito/Powermock. You need Powermock, because Mockito is not able to mock static mehtods:
这是您可以使用 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
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>
回答by Tobias Kremer
You could create a Datacenter interface and have the enum implement the interface. This would make mocking more easy.
您可以创建一个 Datacenter 接口并让枚举实现该接口。这将使嘲笑更容易。
Most of all I would not place configuration information in an Enum to begin with. If you ever have to add an other Datacenter (or the config of a Datacenter changes) you have to recompile the code. Consider putting the configuration in a normal class reading for example a java properties file or a XML file. (This function might be already implement in your framework.)
最重要的是,我不会将配置信息放在 Enum 中。如果您必须添加其他数据中心(或数据中心的配置更改),则必须重新编译代码。考虑将配置放在普通的类读取中,例如 java 属性文件或 XML 文件。(此功能可能已在您的框架中实现。)
If this is not possible you might use "darkes reflaction" magic to change fields in your Enum to the required values.
如果这是不可能的,您可以使用“暗反射”魔法将 Enum 中的字段更改为所需的值。
回答by Rogério
It's easy with JMockit:
使用 JMockit 很容易:
@Test
public void mockInetAddress(@Cascading final InetAddress inetAddress)
{
new NonStrictExpectations() {{
inetAddress.getCanonicalHostName(); result = "foo";
}};
String datacenter = DatacenterEnum.getDatacenter();
assertEquals("foo", datacenter);
}
You could also mock the getHostName()
method in the enum, of course, but it's best to avoid mocking private
methods.
getHostName()
当然,您也可以模拟枚举中的方法,但最好避免模拟private
方法。
回答by meriton
I may be old school, but I'd really refactor the code under test rather than using classloader hacks. Something like:
我可能是老派,但我真的会重构被测代码而不是使用类加载器技巧。就像是:
public enum DatacenterEnum {
DEV, DC1, DC2, DC3;
static String hostName = InetAddress.getLocalHost().getCanonicalHostName().toLowerCase();
public static String getHostName() {
return hostName;
}
}
and in your test code, prior to running the test:
在您的测试代码中,在运行测试之前:
DataCenterEnum.hostName = "foo";