【问题标题】:Injecting values into private field in Quarkus test在 Quarkus 测试中将值注入私有字段
【发布时间】:2021-04-29 14:03:57
【问题描述】:

我正在尝试使用 Quarkus 应用程序中的 FieldSetter 为我的测试类中的私有字段设置值(Quarkus 版本:1.5.2.Final 和 JDK 版本:11)

主类

@ApplicationScoped
public class TokenService{
    @Inject @RestClient RestClientInterface client;

    private String someVariable;

    public String someMethod(){}
}

测试类

@QuarkusTest
public class TokenServiceTest{
    @Inject TokenService service;
    @InjectMock @RestClient RestClientInterface client;

    @Test
    public void someMethodTest(){
       FieldSetter.setField(service, "someVariable", "someValue");
    }
}

但是 FieldSetter 正在抛出 NoSuchField 错误。请帮忙。 也尝试过

service.getClass().getdeclaredField("someVariable")

但同样的问题。

提前致谢。

【问题讨论】:

  • 为什么需要在单元测试中设置私有字段?可能有正当理由,但很可能是设计存在缺陷。
  • 那些在实时工作流中初始化的私有字段有一些到期时间,所以我每次访问该方法时都会检查它是否仍然有效。因此,在测试用例中,我需要为这些私有字段注入一些值。

标签: java reflection mockito junit5 quarkus


【解决方案1】:

TokenService 类是 @ApplicationScoped。这意味着如果您在某处@Inject 它,则该类的实例不会 直接注入。相反,注入的是所谓的客户端代理,它是原始类的子类。该子类负责在每次方法调用时查找正确的实例(并将调用转发给实例)。

这个子类自然不声明someVariable。这就是getDeclaredField("someVariable") 失败的原因。我假设 FieldSetter 来自 Mockito ——在这种情况下,它会做同样的事情并因同样的原因而失败。

您可以将TokenService 设为@Singleton——在这种情况下没有客户端代理并且直接注入一个实例——或者使用客户端代理是子类的知识并简单地查看超类。或者——这可能是最好的——重新设计你的代码,这样你就不必从外部更改private 字段。无论如何,这是一种代码味道。

【讨论】:

  • 感谢您的快速回复。但我有一个疑问,如何在我的测试类中初始化“TokenService”类,因为 InjectMocks 和 InjectMock 注释都没有帮助
  • QuarkusTest 不允许我们使用 Singleton/Dependent 范围。甚至在他们的博客中也提到过。 RequestScope 也给出了同样的错误。
  • 啊,你是对的,mockable beans 必须是正常范围的。但是,如果您不需要模拟 bean,您仍然可以将其设为 @Singleton。它们的不同之处如下:quarkus.io/guides/… 但是,仍然缺少一件关键的事情:为什么需要更改 private 字段?这与嘲笑完全无关,还是有联系?
  • 那些在实时工作流中初始化的私有字段有一些到期时间,所以我每次访问该方法时都会检查它是否仍然有效。因此,在测试用例中,我需要为这些私有字段注入一些值。
  • 为什么不为此创建一个仅测试方法?假设测试与类在同一个包中,则该方法可以是包私有的。我认为这是一件相当普遍的事情。人们经常用特殊用途的注解来标记这些方法,通常称为@VisibleForTesting。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-01
  • 1970-01-01
  • 2017-01-29
  • 1970-01-01
  • 2019-08-01
  • 2012-07-18
  • 1970-01-01
相关资源
最近更新 更多