【问题标题】:Is it possible to mock an enum with Spock?是否可以使用 Spock 模拟枚举?
【发布时间】:2015-05-16 01:39:38
【问题描述】:

我有一个 switch 语句来处理 java enum foo,并且正在使用 spock 编写一些常规单元测试。我已经添加了一个测试,它验证当前处理了每种类型的 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 的方法,因为我在任何文档中都找不到解决方案。

编辑在下面的一些cmets之后,我觉得最好澄清一下我为什么要编写这些测试。

我在一个有很多开发人员的团队中工作,其中一个很可能会更新枚举。如果发生这种情况以使开发人员意识到他们需要添加逻辑来处理新的枚举类型,我希望测试失败。 为此,我编写了一个测试,迭代枚举可能具有的每个可能值,将其传递给方法并验证没有引发异常。现在,如果用户添加了一个新的枚举,这个测试将会失败,因为没有任何东西可以处理它,所以会(希望)抛出一个异常。

第二个测试(我正在努力编写的那个)是为了澄清默认逻辑按我的预期工作,并且实际上确实抛出了异常。在不创建我永远不想使用的枚举值的情况下,我能想到的唯一方法是模拟一个枚举,并测试如果未处理枚举值是否会引发异常。

代码如下:

枚举 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);
}

【问题讨论】:

  • 请提供样品测试。
  • @Opal 我已经添加了上面的示例测试。
  • 我们需要模拟枚举吗?
  • @Ramsharan,好问题!
  • @BenGreen 您能否发布您尝试使用模拟枚举编写测试的实际代码逻辑?

标签: java unit-testing groovy enums spock


【解决方案1】:

以下规范将涵盖添加新枚举而不为其提供服务逻辑:

def 'no exception thrown for all enums'() {
    given:
    def service = new SampleService()

    when:
    service.handleFoo(se)

    then:
    noExceptionThrown()

    where:
    se << SampleEnum.values()
}

我尝试编写一个测试来模拟枚举或在测试运行时添加另一个值,但现在失败了。稍后会回到它。

Spock 不支持模拟枚举。

【讨论】:

  • 谢谢。我实际上已经接受了这个测试。正如我所说,只是在测试默认块时挣扎。
  • @BenGreen,当然。正如我所说,稍后会回到它。但是 spock 不支持模拟枚举。
  • @BenGreen,我尝试过使用EnumBuster:javaspecialists.eu/archive/Issue161.html,它与java 完美配合,但是groovy 有一些问题。我不会在合理的时间内修复它,因此您可以暂时将我的答案视为最终答案。
  • 好的,谢谢。我会根据“Spock 不支持模拟枚举”位接受您的回答。感谢所有的工作。
【解决方案2】:

这个问题很老,我在考虑如何覆盖default: 分支。我还查看了评论中提到的 EnumBuster 解决方法。顺便说一下,这里是一个EnumBuster update,用于获取最新的 Java 版本。

无论如何,我认为使用工具——我宁愿称之为肮脏的把戏——并不是一个特别好的主意。可能,在您的构建配置中添加一个涵盖该案例的静态代码分析工具会更好。我快速检查了 Checkstyle、PMD、SonarQube 和 FindBugs 的默认规则集,但没有找到完全符合我们需要的规则,但 Eclipse 和 IntelliJ IDEA 都有内置的检查功能。它们也是可配置的,即发出警告或构建错误,如果有 default: 子句,仍然会发出警告/失败:

也许某处有一个我刚刚没有找到的流行静态代码分析工具之一的自定义规则。当然,您也可以编写自定义规则。优点是它适用于整个项目或潜在的许多项目,可重复使用且不需要额外测试。

如果您痴迷于这种极端情况的测试覆盖率,那么静态代码分析工具当然帮不了您。然后你仍然可以在你的测试类路径上放置一个带有额外虚拟值的自定义版本的枚举(可能作为原始源文件的派生自动生成),以覆盖默认情况或抛出的异常,否则永远不会到达在 switch 块之后。

【讨论】:

    【解决方案3】:

    正如这里所解释的https://www.baeldung.com/java-extending-enums 您可以为 Enum 创建一个接口并模拟该接口。

    【讨论】:

      猜你喜欢
      • 2012-02-13
      • 1970-01-01
      • 2016-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-04
      • 1970-01-01
      相关资源
      最近更新 更多