我试图为我的程序中用于验证表单的简单bean编写单元测试。该bean使用@Component进行注释,并且有一个初始化使用的类变量

@Value("${this.property.value}") private String thisProperty;

我想为这个类中的验证方法编写单元测试,但是,如果可能的话,我想这样做而不使用属性文件。我这样做的原因是,如果我从属性文件中提取的值发生了变化,我希望它不影响我的测试用例。我的测试用例是测试验证值的代码,而不是值本身。

是否有一种方法可以在我的测试类中使用Java代码来初始化一个Java类,并在该类中填充Spring @Value属性,然后使用它来测试?

我确实发现这个如何,似乎是接近,但仍然使用一个属性文件。我宁愿全部都是Java代码。


当前回答

这似乎是可行的,尽管仍然有点啰嗦(我想要更短的东西):

@BeforeClass
public static void beforeClass() {
    System.setProperty("some.property", "<value>");
}

// Optionally:
@AfterClass
public static void afterClass() {
    System.clearProperty("some.property");
}

其他回答

如果可能的话,我会尝试在没有Spring Context的情况下编写这些测试。如果您在没有spring的测试中创建这个类,那么您可以完全控制它的字段。

要设置@value字段,您可以使用Springs ReflectionTestUtils -它有一个方法setField来设置私有字段。

@see JavaDoc: ReflectionTestUtils.setField(java.lang)Object, java . lang。管柱,java . lang . Object)

在springboot 2.4.1中,我刚刚在我的测试中添加了注释@SpringBootTest,显然,在我的src/test/resources/application.yml中设置了spring.profiles.active = test

我使用@ExtendWith({SpringExtension.class})和@ContextConfiguration(类= {RabbitMQ.class, GenericMapToObject.class, ModelMapper.class, StringUtils.class})进行外部conf

从Spring 4.1开始,你可以在代码中通过在单元测试类级别上使用org.springframework.test.context.TestPropertySource注释来设置属性值。您甚至可以使用这种方法向依赖bean实例注入属性

例如

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = FooTest.Config.class)
@TestPropertySource(properties = {
    "some.bar.value=testValue",
})
public class FooTest {

  @Value("${some.bar.value}")
  String bar;

  @Test
  public void testValueSetup() {
    assertEquals("testValue", bar);
  }


  @Configuration
  static class Config {

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertiesResolver() {
        return new PropertySourcesPlaceholderConfigurer();
    }

  }

}

注意:在Spring上下文中必须有org.springframework.context.support.PropertySourcesPlaceholderConfigurer实例

编辑24-08-2017:如果你使用SpringBoot 1.4.0及以后版本,你可以用@SpringBootTest和@SpringBootConfiguration注解初始化测试。更多信息请点击这里

对于SpringBoot,我们有以下代码

@SpringBootTest
@SpringBootConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@TestPropertySource(properties = {
    "some.bar.value=testValue",
})
public class FooTest {

  @Value("${some.bar.value}")
  String bar;

  @Test
  public void testValueSetup() {
    assertEquals("testValue", bar);
  }

}

如果您愿意,您仍然可以在Spring Context中运行测试,并在Spring配置类中设置所需的属性。如果您使用JUnit,请使用SpringJUnit4ClassRunner并为您的测试定义专用配置类,如下所示:

被测类:

@Component
public SomeClass {

    @Autowired
    private SomeDependency someDependency;

    @Value("${someProperty}")
    private String someProperty;
}

测试类:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = SomeClassTestsConfig.class)
public class SomeClassTests {

    @Autowired
    private SomeClass someClass;

    @Autowired
    private SomeDependency someDependency;

    @Before
    public void setup() {
       Mockito.reset(someDependency);

    @Test
    public void someTest() { ... }
}

和这个测试的配置类:

@Configuration
public class SomeClassTestsConfig {

    @Bean
    public static PropertySourcesPlaceholderConfigurer properties() throws Exception {
        final PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
        Properties properties = new Properties();

        properties.setProperty("someProperty", "testValue");

        pspc.setProperties(properties);
        return pspc;
    }
    @Bean
    public SomeClass getSomeClass() {
        return new SomeClass();
    }

    @Bean
    public SomeDependency getSomeDependency() {
        // Mockito used here for mocking dependency
        return Mockito.mock(SomeDependency.class);
    }
}

话虽如此,我不推荐这种方法,我只是在这里添加它作为参考。在我看来,更好的方法是使用Mockito runner。在这种情况下,您根本不需要在Spring中运行测试,这更加清晰和简单。

这似乎是可行的,尽管仍然有点啰嗦(我想要更短的东西):

@BeforeClass
public static void beforeClass() {
    System.setProperty("some.property", "<value>");
}

// Optionally:
@AfterClass
public static void afterClass() {
    System.clearProperty("some.property");
}