【问题标题】:Junit - Spring boot: @Value is always null while testingJunit - Spring boot:@Value 在测试时始终为空
【发布时间】:2022-01-06 04:40:05
【问题描述】:

有一个@Value注解的常量,在运行测试时没有初始化,在构造函数中需要它时抛出NullPointerException。

要测试的示例类:

class TestClass {
    @Value("${test.value1}")
    private String value1;

    private final TestTemplate testTemplate;

    public TestClass(TestTemplateBuilder builder) {
        testTemplate = builder.someMethod(value1).build();
    }


    ---
}

示例测试类:

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = TestClass.class)
@SpringBootTest
class TestClassTest {

    @MockBean
    TestTemplateBuilder builder;

    @Autowired
    TestClass testClass = new TestClass(testTemplate);

    @Before
    public void setUp() {
        ReflectionTestUtils.setField(testClass, "value1", "VALUE");

        Mockito.when(builder.build()).thenReturn(new TestTemplate());
    }

    ---
}

尝试过,但没有任何效果:

  • 我创建了具有所需值的application.properties 文件。
  • 创建application-test.properties并添加@TestPropertySource(locations="classpath:application-test.properties")
  • @SpringBootTest(properties = { "test.value1=VALUE" })

我也尝试了一些其他的东西,但我得到的是NullPoiterExceptionsomeMethod(value1)

版本:

  • Java:1.8
  • Springboot:2.1.17
  • 六月:4.12
  • 模拟:2.23.4

【问题讨论】:

  • 我能说什么...抛弃 Mockito 并改用 Spock,然后添加 @SpringBootTest 注释,您将免费获得完整的测试容器。
  • 您正在自己创建一个TestClass 的实例。它没有注入或处理任何东西。删除 new TestClass 以初始化该字段。此外,您应该注册行为,但您已经在构造函数中调用了模拟,所以这是不可能的。您应该做的是不要使用 Spring 进行此测试,自己创建模拟和实例并运行测试。您不必对所有事情都使用 Spring,尤其是如果您想编写一个简单的单元测试。
  • @M.Deinum 我明白了删除不必要的东西的意义。您能否分享一个示例或一些链接以帮助我理解。

标签: java spring-boot junit mockito context-configuration


【解决方案1】:

只是为了确保(因为在问题中,它没有显示): TestClass 的类是 Spring bean(组件、服务...)?

编辑(TestClassis 组件):

Spring bean 不是这样创建的;

如果TestClass 的构造函数需要@Value,那么只有Spring 会保证在实例化TestClass 之前test.value1 值可用。 所以你可以在构造函数中添加@Value("${test.value1}")String value1并设置value1属性。

请阅读Spring注入方式。

【讨论】:

  • 这是一个Component
  • @towardinfinity 我编辑了答案
  • 我得到了你所说的观点,所以问题出在TestClassTestClass 不是我写的,所以我现在无法更改,但将来会更改。
【解决方案2】:

您收到 NullPointerException 的原因是值注入发生在构造函数调用之后。为了防止这种情况,您可以在构造函数调用后使用 spring 生命周期钩子来初始化您的类。

【讨论】:

  • value1 在构造函数内部使用,因此它的值应该在构造函数调用之前被初始化。正如你所说的在构造函数调用之后发生值注入你可以通过一些文档来支持它吗?
【解决方案3】:

我无法解决主要问题,但我满足了这样的要求。

class TestClassTest {

    TestClass testClass;

    @Before
    public void setUp() {
        TestTemplateBuilder builder = Mockito.mock(TestTemplateBuilder.clsss);

        TestTemplateBuilder builder1 = Mockito.mock(TestTemplateBuilder.clsss);

        Mockito.when(builder.someMethod(nullable(String.class))).thenReturn(builder1);

        Mockito.when(builder1.build()).thenReturn(new TestTemplate());

        testClass = new TestClass(builder);
    }

    ---
}

这可能不是正确的做法。

【讨论】:

    猜你喜欢
    • 2015-09-02
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 2018-02-12
    • 2016-12-24
    • 2018-08-27
    • 2019-10-26
    相关资源
    最近更新 更多