java 不识别enum_关于java:Unit Test for Enum值不存在?
首先是一些示例代码...
枚举:
public enum TestEnum {
YES,
NO
}
一些代码:
public static boolean WorkTheEnum(TestEnum theEnum) {
switch (theEnum) {
case YES:
return true;
case NO:
return false;
default:
// throws an exception here
}
}
问题:
我从其他开发人员的不同代码中导入了TestEnum。 因此它实际上可以改变。 对于这种情况,我想要一个单元测试来实际检查该不存在的值。 但是我根本不知道如何使用Mockito和JUnit做到这一点。
这部分当然不起作用:
@Test(expected=Exception.class)
public void DoesNotExist_throwsException() throws Exception {
when(TestEnum.MAYBE).thenReturn(TestEnum.MAYBE);
WorkTheEnum(TestEnum.MAYBE);
}
我找到了一个使用PowerMock的示例,但无法使其与Mockito一起使用。
有任何想法吗?
我没有足够的信心声称这是答案,但是:是否不可能做TestEnum notAValidEnum = Mockito.mock(TestEnum.class);,然后将其提供给WorkTheEnum() ...?
可能重复:stackoverflow.com/questions/5323505
可能相关:stackoverflow.com/questions/28013717/
以@assylias的答案为基础,我认为这是您可以做的最好的事情:
List unknown = new ArrayList<>();
for (TestEnum e : TestEnum.values())
unknown.add(e.name());
unknown.removeAll(Arrays.asList("YES","NO"));
if (unknown.isEmpty()) {
// Not possible to reach default case, do whatever you need to do
} else {
TestEnum notIncluded = TestEnum.valueOf(unknown.get(0));
workTheEnum(notIncluded);
}
由于enum switch语句的编译方式,不可能(AFAIK)伪造switch语句中不存在的enum值。即使您通过反射摆弄enum实例中的内部ordinal字段,switch语句也将给出ArrayIndexOutOfBoundsException而不是陷入default情况。
由于上面提到的ArrayIndexOutOfBoundsException,以下代码看起来可能可行,但无效:
TestEnum abused = TestEnum.YES;
try {
Class< ? > c = abused.getClass().getSuperclass();
Field[] declaredFields = c.getDeclaredFields();
Field ordinalField = null;
for (Field e : declaredFields) {
if (e.getName().equals("ordinal")) {
ordinalField = e;
}
}
ordinalField.setAccessible(true);
ordinalField.setInt(abused, TestEnum.values().length);
workTheEnum(abused);
} catch (Exception e) {
e.printStackTrace(System.err);
}
好的,这可能对您有用。这很hacky,所以对我来说,可能比没有100%代码覆盖率YMMV更糟糕。它通过用包含全零的数组替换枚举有序查找数组来工作,这属于默认情况。
// Setup values - needs to be called so that
// $SWITCH_TABLE$FooClass$BarEnum is initialised.
workTheEnum(TestEnum.YES);
workTheEnum(TestEnum.NO);
// This is the class with the switch statement in it.
Class< ? > c = ClassWithSwitchStatement.class;
// Find and change fields.
Map changedFields = new HashMap<>();
Field[] declaredFields = c.getDeclaredFields();
try {
for (Field f : declaredFields) {
if (f.getName().startsWith("$SWITCH_TABLE$")) {
f.setAccessible(true);
int[] table = (int[])f.get(null);
f.set(null, new int[table.length]);
changedFields.put(f, table);
}
}
workTheEnum(TestEnum.YES);
} finally {
for (Map.Entry entry : changedFields.entrySet()) {
try {
entry.getKey().set(null, entry.getValue());
} catch (Exception ex) {
ex.printStackTrace(System.err);
}
}
}
也许嘲笑不是正确的方法吗?但是必须有一种使用反射添加值的方法,以便枚举实际上是有效的并且具有所有这些值!
不,我不这么认为。编译switch语句时,将生成一个数组,其中包含该时间点存在的枚举值的所有序号。如果尝试修改现有值以更改其序数,则编译器生成的代码将访问数组范围之外的值,并失败并显示ArrayIndexOutOfBoundsException。糟糕的是附加了一些执行此操作的代码,以便您可以查看是否喜欢。
感谢您详细的答复@msandiford。我想运气不好。
对我来说,它仅在将f.setAccessible(true);添加到循环中时才有效(请参阅我的编辑)。这可能与Java8有关吗?
另一个注意事项:对我来说,它不适用于Maven(->在此排除它)。一旦Maven使用开关编译了该类,就必须再次在Eclipse中编译该类以使测试再次在Eclipse中工作。换句话说,无论测试是否有效,编译器都起着重要的作用。
一个简单的怎么样:
Set expected = new HashSet<> (Arrays.asList("YES","NO"));
Set actual = new HashSet<>();
for (TestEnum e : TestEnum.values()) actual.add(e.name());
assertEquals(expected, actual);
(使用HashSet而不是ArrayList,因为顺序无关紧要)
但这只会测试枚举的内容,而不会测试switch语句的默认路径。
我明白了-如果要达到默认大小写,您想确保该方法引发异常,因此您想模拟枚举以模拟非预期值。那正确吗?
那正是我想做的,是的。
@Feroc的问题是您无法通过反射实例化枚举的新实例,因此我不确定mockito是否可以解决该限制...
Mockito不支持枚举值的模拟,但powermock则支持。
尝试这个。
我创建了自己的类来模拟它们。请映射到您自己的班级。
@RunWith(PowerMockRunner.class)
@PrepareForTest(Trail.class)
public class TrailTest {
@Before
public void setUp() {
Trail mockTrail = PowerMock.createMock(Trail.class);
Whitebox.setInternalState(mockTrail,"name","Default");
Whitebox.setInternalState(mockTrail,"ordinal", 2);
PowerMock.mockStatic(Trail.class);
expect(Trail.values()).andReturn(new Trail[]{Trail.YES, Trail.NO, mockTrail});
expect(Trail.valueOf("default value")).andReturn(mockTrail);
PowerMock.replay(Trail.class);
}
@Test(expected = RuntimeException.class)
public void test() {
Trail aDefault = Trail.valueOf("default value");
BasicTrails.find(aDefault);
}
}
这是方法:
public class BasicTrails {
public static boolean find(Trail trail) {
switch (trail) {
case YES:
return true;
case NO:
return false;
default:
throw new RuntimeException("Invalid");
}
}
这是枚举
public enum Trail {
YES, NO;
}
谢谢你的帮助。不太确定我们是否可以在此处使用Powermock。
它只是另一个mock库。无论如何,这取决于选择。
如果您将代码转换为OP问题,则可以改善答案
@VinayVeluri:PowerMock不仅仅是另一个模拟库。它比Mockito更强大,这就是为什么有些人不想在项目中使用它的原因。它用于测试遗留代码,例如静态方法无法通过Mockito等"常规"模拟库进行测试。只要您开发一个新项目,就应该以不需要PowerMock的方式进行开发,但是Mockito就足够了。
借助Powermock,我们可以实现此目标,因为Powermock支持模拟最终类
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.BDDMockito;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(Trail.class)
public class TrailTest {
@Mock Trail mockTrail;
@Before
public void setUp() {
PowerMockito.mockStatic(Trail.class);
BDDMockito.given(Trail.values()).willReturn(new Trail[]{Trail.YES, Trail.NO, mockTrail});
BDDMockito.given(Trail.valueOf("YES")).willReturn(mockTrail.YES);
BDDMockito.given(Trail.valueOf("NO")).willReturn(mockTrail.NO);
}
@Test
public void test() {
assertTrue(BasicTrails.find(mockTrail.valueOf("YES")));
assertFalse(BasicTrails.find(mockTrail.valueOf("NO")));
try{
Trail aDefault = mockTrail.valueOf("default value");
}catch (Exception e) {
System.out.println(e);
}
}
}
您可以嘲笑,修改或尝试使其工作,但是有一种非常简单的方法来做到这一点。我假设您正在使用Maven或Gradle,因此您具有main和test配置文件。
然后在主配置文件中,您将得到上面的代码:
package my.cool.package;
public enum TestEnum {
YES,
NO
}
但是在测试配置文件中,您可以拥有另一个:
// EXACTLY SAME as above
package my.cool.package;
public enum TestEnum {
YES,
NO,
INVALID_FOR_TEST_ONLY
}
现在您可以在测试中使用新值INVALID_FOR_TEST_ONLY,并且在产品概要文件中将不可用。
有两个缺点:
如果您更新产品枚举,则可能还需要更新测试(如果要进行测试,则需要更新)
某些IDE可能无法正确使用此技巧,即使Maven很好理解它
java 不识别enum_关于java:Unit Test for Enum值不存在?相关推荐
- java 音乐识别_使用java获取歌曲的属性
今天使用java写了一个简单的android播放器,感觉还不错,就是向更加的完善一点上网搜索了一下获取音乐对象的属性,比如,作者,专辑,时间的大小.看到一个比较好的例子,贴出来给大家分享. publi ...
- java代码识别_识别Java中的代码气味
java代码识别 作为软件开发人员,我们不仅要编写有效的代码,而且还要编写可维护的代码,这是我们的责任. Martin Fowler在他的<重构:改进现有代码的设计>中将代码气味定义为: ...
- Java中识别二维码并且提高二维码的识别率
我们在Java开发的时候,发现对二维码的识别是不足的.所以我们需要提高识别率. 第一步.识别图片二维码.准备相应的jar包.我们在gradle+idea中开发. compile group: 'com ...
- java代码自动抠图_Opencv java实现人脸抠图和行为识别
基于java的OpenCV环境搭建(Windows平台上ecplise) https://blog..net/qq_32447301/article/details/78494913 https:// ...
- Java 扫描识别条形码图片
1.条形码扫描识别的实现方法及步骤 本文以Java代码示例介绍如何来扫描和识别条形码图片.这里使用免费的条码工具Free Spire.Barcode for Java,调用BarcodeScanner ...
- java人体识别_【人体分析-人像分割】JavaAPI示例代码
接口能力: 对于输入的一张图片(可正常解码,且长宽比适宜),识别人体的轮廓范围,与背景进行分离,适用于拍照背景替换.照片合成.身体特效等场景.输入正常人像图片,返回分割后的二值结果图和分割类型(目前仅 ...
- java条码识别技术_Java 生成、识别条形码
条形码是由一定的字符,数字及符号组成,用以表达一组信息的图形标识符.它可以标出物品的商品名称.生产日期.图书分类号,邮件起止地点等.因而在商品流通.图书管理.邮政管理等许多领域得以广泛的应用.本文将通 ...
- java ocr识别中文_java零碎要点—Tesseract 3.0,Java OCR 图像智能字符识别技术,可识别中文 | 学步园...
2.Java OCR 图像智能字符识别技术,可识别中文 几天一直在研究OCR技术,据我了解的情况,国内最专业的OCR软件只有2家,清华TH-OCR和汉王OCR,看了很多的OCR 技术发现好多对英文与数 ...
- java ocr 识别中文
几天一直在研究OCR技术,据我了解的情况,国内最专业的OCR软件只有2家,清华TH-OCR和汉王OCR,看了很多的OCR技术发现好多对英文与数字的支持都很好,可惜很多都不支持中文字符.Asprise- ...
最新文章
- MetagenoNets:在线宏基因组网络分析实操教程
- tensorflow-tf.train.shuffle_batch
- 数据类型,运算符和表达式02 - 零基础入门学习C语言03
- Python编程中一些异常处理的小技巧
- 【Jmeter篇】如何利用Jmeter配置元件计数器、随机变量制造批量数据和变量参数化?
- TreeView 之间节点拖动 /移动
- 【C++】max_element() 和 min_element()
- Learn OpenGL(五)——定义自己的着色器
- android c++标准命名空间demo
- mysql数据库原理与应用武洪萍第三张答案_MySQL数据库原理及应用(第2版)(微课版)...
- 怎么彻底删除mysql服务_mysql怎么卸载干净?
- 同志亦凡人第一季/全集BQueer As Folk 1迅雷下载
- 数据集成-3-数据集成框架
- Cydia Tweak
- java虚拟机 方法区_java虚拟机---方法区[szx]
- RGB转CMY最简单的方法
- 【DOM】DOM概述及DOM操作之如何查找元素_01
- 第000篇 - 一步一步了解区块链技术
- 智慧应管理信息化 平台建设方案
- 中国系统java开发面试准备
热门文章
- wxWidgets:wxListCtrl类用法
- wxWidgets:wxCalculateLayoutEvent类用法
- boost::mpi模块实现scan集合的测试
- boost::mp11::mp_partition_q相关用法的测试程序
- boost::describe模块宏BOOST_DESCRIBE_PP_IS_PAREN的测试程序
- ITK:向二进制图像添加噪声
- VTK:可视化之BackgroundGradient
- VTK:Utilities之Coordinate
- VTK:Math之PerpendicularVector
- VTK:几何对象之CellTypeSource