【问题标题】:Using Spock to mock private static final variables in Java使用 Spock 在 Java 中模拟私有静态最终变量
【发布时间】:2014-12-18 17:43:26
【问题描述】:

我正在尝试使用 Groovy 编写一些 Spock 测试来测试一些 Java 代码(特别是 servlet 过滤器)。我有一些我想模拟的private staticprivate static final 变量,但我无法确定是否有办法做到这一点。我知道metaClass 可用于方法,变量有类似的吗?

例如,我有:

public class MyFilter implements Filter {
  private static WebResource RESOURCE;
  private static final String CACHE_KEY = "key-to-be-used-for-cache";
  ... actual methods, etc ...
}

我尝试过使用Mock(MyFilter),以及使用Java反射来改变值(基于这个问题和答案Change private static final field using Java reflection)。

我想在不添加 Mockito 或其他框架之类的东西的情况下执行此操作,如果可能的话,只需使用普通的 Groovy 和 Spock。

感谢您的任何想法!

更新 1

至少对于 private static 变量,我确实得到了以下工作:

Field field = MyFilter.class.getDeclaredField("CACHE_KEY")
field.setAccessible(true)
field.set(null, "new-key-value")

但我仍然无法绕过final 方面。

更新 2

感谢 Xv。我现在可以使用以下设置:

Field field = MyFilter.class.getDeclaredField("CACHE_KEY")
field.setAccessible(true)

Field modifiersField = Field.class.getDeclaredField("modifiers")
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

field.set(null, "new-key-value")

【问题讨论】:

  • 我想这取决于它是如何被测试的,但 IMO 使用旨在做你想做的事情的框架是更好的方法,并且更广泛适用,例如,java.dzone.com/articles/mocking-static-methods-groovy 和 @ 987654323@等
  • 感谢您的评论 @DaveNewton - 特别是 Peter Niederwieser 指出在 Spock 中只能模拟 groovy 定义的方法。我的案例特定于类字段/变量,但我将检查其他框架之一是否能够为我执行此操作。谢谢。
  • 我知道这不是你要找的东西,但不久前我玩弄了Spock and PowerMock 的组合来模拟静态方法。我不记得它是否也适用于(最终)静态成员,请自己尝试。但我真正想说的是,如果你的代码很难测试,你不应该升级你的测试或测试工具,而是重构代码以提高可测试性。我认为,每当您需要诸如您想要的技巧或工具来提供您想要的东西时,这就是 代码味道
  • 为什么不添加其他框架?有什么特别的原因吗?
  • 主要问题是似乎很多框架都可以处理一个困难的测试场景(模拟决赛,模拟构造函数等),过去我尝试添加每个框架来获得我需要一件,那只会弄得一团糟。我希望尽可能地简化依赖关系——这也将有助于减少每个不同框架引入的不同编码范例。

标签: java unit-testing groovy spock


【解决方案1】:

根据我从 https://stackoverflow.com/a/25031713/239408 那里学到的知识,这在 spock 中对我有用

import java.lang.reflect.Field
import java.lang.reflect.Modifier

...

    def setup() {

        Field field = BackendCredentials.getDeclaredField("logger")
        field.setAccessible(true);

        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

        field.set(null, Mock(Logger))
    }

看起来您缺少取消设置 Modifier.FINAL 标志。

【讨论】:

    【解决方案2】:

    您要么需要使用 PowerMock(或其他类似的解决方案),要么重构您的代码。 Spock 本身不支持模拟私有/静态/最终方法。 Mockito 中也存在此限制,因此必须为您提供有关最佳实践的提示。

    【讨论】:

      猜你喜欢
      • 2022-09-25
      • 1970-01-01
      • 1970-01-01
      • 2018-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-05
      相关资源
      最近更新 更多