我有一个switch语句来处理java enum foo,并且使用spock来编写一些groovy单元测试。我已经添加了一个测试,它验证当前是否处理了每种类型的foo而没有抛出异常。现在我想测试一个无法识别的foo类型会导致抛出异常。
要做到这一点,我将不得不嘲笑枚举,并且已经看到了这里概述的解决方案: Mocking Java enum to add a value to test fail case
我也知道可以使用powermock,但我真的很喜欢spock,因为我发现它非常轻巧,所以正在寻找使用spock的解决方案。
我认为这样的事可能有用:
def "An unexpected type of foo causes an exception to be thrown"() {
given:
Foo foo = Mock()
when:
subjectUnderTest.handleFoo foo
then:
thrown Exception
}
但是,此操作失败,并显示以下错误消息:
org.spockframework.mock.CannotCreateMockException: Cannot create mock for class com.Foo because Java mocks cannot mock final classes. If the code under test is written in Groovy, use a Groovy mock.
我想知道是否有人知道使用spock的方法,因为我无法找到任何文档的解决方案。
编辑在下面的一些评论之后,我觉得最好澄清一下我为什么要编写这些测试。
我在一个有很多开发人员的团队中工作,很可能他们中的一个会更新枚举。我希望测试失败,如果这恰好使开发人员意识到他们需要添加逻辑来处理新的枚举类型。 为此,我编写了一个测试,迭代枚举可能具有的每个可能值,将其传递给方法并验证不会抛出异常。现在,如果用户添加了新的枚举,则此测试将失败,因为没有任何东西可以处理它,因此会(有希望)抛出异常。
第二个测试(我正在努力编写的那个)是为了澄清默认逻辑的工作方式与我期望的一样,并且实际上会抛出异常。在没有创建我永远不想使用的枚举值的情况下,我能想到这样做的唯一方法是模拟枚举,并测试如果不处理枚举值则抛出异常。
代码如下所示:
Enum Foo:
public enum Foo {
ONE, TWO;
}
处理foo的方法:
private void handleFoo(Foo foo) {
switch (foo) {
case ONE:
doEventOne();
break;
case TWO:
doEventTwo()
break;
default:
throw new IllegalArgumentException("Do not know how to handle " + foo);
}
答案 0 :(得分:6)
以下规范将涵盖添加新枚举而不为其提供服务逻辑:
def 'no exception thrown for all enums'() {
given:
def service = new SampleService()
when:
service.handleFoo(se)
then:
noExceptionThrown()
where:
se << SampleEnum.values()
}
我尝试编写一个测试,它将模拟枚举或在测试运行时添加另一个值,但现在失败了。稍后会回到它。
Spock不支持模拟枚举。
答案 1 :(得分:0)
这个问题很老了,我正在考虑如何覆盖 default:
分支。我还查看了评论中提到的 EnumBuster 解决方法。顺便说一下,这是更新 Java 版本的 EnumBuster update。
无论如何,我认为使用工具 - 我宁愿称之为肮脏的技巧 - 就像那样不是一个特别好的主意。可能,将涵盖这种情况的静态代码分析工具添加到您的构建配置中会更好。我很快检查了 Checkstyle、PMD、SonarQube 和 FindBugs 的默认规则集,但没有找到完全符合我们需要的规则,但是 Eclipse 和 IntelliJ IDEA 都内置了检查。它们也是可配置的,即发出警告或构建错误,如果有 default:
子句或没有警告/失败:
也许在某个地方,我没有找到一种流行的静态代码分析工具的自定义规则。当然,您也可以编写自定义规则。优点是它适用于整个项目或潜在的许多项目,可重复使用,不需要额外的测试。
如果您沉迷于这种极端情况的测试覆盖率,那么静态代码分析工具当然不会帮到您。然后你仍然可以在你的测试类路径上放置一个带有额外虚拟值的自定义版本的枚举(可能作为原始源文件的派生自动生成)以覆盖默认情况或抛出的异常,否则永远不会到达在 switch 块之后。