Java 单元测试期间填充弹簧@值
我正在尝试为一个简单bean编写一个单元测试,该bean在我的程序中用于验证表单。bean用Java 单元测试期间填充弹簧@值,java,spring,junit,spring-annotations,Java,Spring,Junit,Spring Annotations,我正在尝试为一个简单bean编写一个单元测试,该bean在我的程序中用于验证表单。bean用@Component注释,并有一个使用 @Value("${this.property.value}") private String thisProperty; 我想在这个类中为验证方法编写单元测试,但是,如果可能的话,我不想使用属性文件。我的理由是,如果我从属性文件中提取的值发生变化,我希望这不会影响我的测试用例。我的测试用例是测试验证值的代码,而不是值本身 有没有办法在我的测试类中使用Java代码
@Component
注释,并有一个使用
@Value("${this.property.value}") private String thisProperty;
我想在这个类中为验证方法编写单元测试,但是,如果可能的话,我不想使用属性文件。我的理由是,如果我从属性文件中提取的值发生变化,我希望这不会影响我的测试用例。我的测试用例是测试验证值的代码,而不是值本身
有没有办法在我的测试类中使用Java代码来初始化Java类,并在该类中填充Spring@Value属性,然后使用该属性进行测试
我确实发现这似乎很接近,但仍然使用属性文件。我宁愿它都是Java代码。如果可能的话,我会尝试在没有Spring上下文的情况下编写这些测试。如果您在没有spring的测试中创建这个类,那么您可以完全控制它的字段 要设置
@value
字段,可以使用Springs-它有一个设置私有字段的方法
@如果需要,请参见,您仍然可以在Spring上下文中运行测试,并在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
类()之前的公共静态void{
System.setProperty(“some.property”,”);
}
//可选:
@下课
公共静态void afterClass(){
System.clearProperty(“some.property”);
}
在配置中添加PropertyPlaceHolderConfigure对我很有效
@Configuration
@ComponentScan
@EnableJpaRepositories
@EnableTransactionManagement
public class TestConfiguration {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
builder.setType(EmbeddedDatabaseType.DERBY);
return builder.build();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPackagesToScan(new String[] { "com.test.model" });
// Use hibernate
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
entityManagerFactoryBean.setJpaProperties(getHibernateProperties());
return entityManagerFactoryBean;
}
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.show_sql", "false");
properties.put("hibernate.dialect", "org.hibernate.dialect.DerbyDialect");
properties.put("hibernate.hbm2ddl.auto", "update");
return properties;
}
@Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
entityManagerFactory().getObject()
);
return transactionManager;
}
@Bean
PropertyPlaceholderConfigurer propConfig() {
PropertyPlaceholderConfigurer placeholderConfigurer = new PropertyPlaceholderConfigurer();
placeholderConfigurer.setLocation(new ClassPathResource("application_test.properties"));
return placeholderConfigurer;
}
}
在测试课上
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfiguration.class)
public class DataServiceTest {
@Autowired
private DataService dataService;
@Autowired
private DataRepository dataRepository;
@Value("${Api.url}")
private String baseUrl;
@Test
public void testUpdateData() {
List<Data> datas = (List<Data>) dataRepository.findAll();
assertTrue(datas.isEmpty());
dataService.updateDatas();
datas = (List<Data>) dataRepository.findAll();
assertFalse(datas.isEmpty());
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(类=TestConfiguration.class)
公共类数据服务测试{
@自动连线
私有数据服务数据服务;
@自动连线
私有数据存储库;
@值(“${Api.url}”)
私有字符串baseUrl;
@试验
公共void testUpdateData(){
List datas=(List)dataRepository.findAll();
assertTrue(datas.isEmpty());
dataService.updateDatas();
datas=(List)dataRepository.findAll();
assertFalse(datas.isEmpty());
}
}
自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.propertysourcesplaceplaceconfigurer
的实例
编辑2017年8月24日:如果您使用的是SpringBoot 1.4.0及更高版本,则可以使用和注释初始化测试。更多信息
对于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);
}
}
不要滥用通过反射获取/设置的私有字段 在这里,我们可以避免使用在几个答案中使用的反射。
它在这里带来的价值很小,但也存在多个缺点:
- 我们只在运行时检测反射问题(例如:不再存在字段)
- 我们需要封装,但不是一个不透明的类,它隐藏了应该可见的依赖项,并使该类更不透明、更不易测试
- 它鼓励糟糕的设计。今天,您声明了一个
。明天您可以在该类中声明@值字符串字段
或5
,您甚至可能没有意识到您降低了该类的设计。使用一种更直观的方法来设置这些字段(例如构造函数),在添加所有这些字段之前,您将三思而后行,您可能会将它们封装到另一个类中,并使用10
@ConfigurationProperties
在不需要的情况下在单元测试中运行容器是一种降低本地构建速度的糟糕做法:您不希望这样。
我添加了这个答案,因为这里的答案似乎没有显示这种区别,所以它们系统地依赖于一个运行的容器 因此,我认为应该移动定义为类内部的属性:
@Component
public class Foo{
@Value("${property.value}") private String property;
//...
}
到将由Spring注入的构造函数参数中:
@Component
public class Foo{
private String property;
public Foo(@Value("${property.value}") String property){
this.property = property;
}
//...
}
单元测试示例
借助构造函数,您可以在不使用Spring的情况下实例化Foo
,并为属性
注入任何值:
public class FooTest{
Foo foo = new Foo("dummyValue");
@Test
public void doThat(){
...
}
}
集成测试示例
由于@SpringBootTest
的属性,您可以通过这种简单的方式将属性注入到springboot上下文中:
@SpringBootTest(properties="property.value=dummyValue")
public class FooTest{
@Autowired
Foo foo;
@Test
public void doThat(){
...
}
}
您可以将其用作备选方案@TestPropertySource
,但它添加了一个附加注释:
@SpringBootTest
@TestPropertySource(properties="property.value=dummyValue")
public class FooTest{ ...}
有了Spring(没有Spring Boot),应该会有点复杂,但由于我很久没有使用Spring而没有Spring Boot,所以我不想说一句愚蠢的话
附带说明:如果要设置多个@Value
字段,请将它们提取到用@ConfigurationProperti注释的类中
@SpringBootTest
@TestPropertySource(properties="property.value=dummyValue")
public class FooTest{ ...}
class ExampleClass{
@Autowired
private Dog dog;
@Value("${this.property.value}")
private String thisProperty;
...other stuff...
}
class ExampleClass{
private Dog dog;
private String thisProperty;
//optionally @Autowire
public ExampleClass(final Dog dog, @Value("${this.property.value}") final String thisProperty){
this.dog = dog;
this.thisProperty = thisProperty;
}
...other stuff...
}
@ExtendWith(SpringExtension.class) // @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(initializers = ConfigDataApplicationContextInitializer.class)