Reputation: 2551
I'm using a Spring Boot app which runs my src/main/resources/config/application.yml
file.
When I run my test case by :
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest
public class MyIntTest{
}
The test codes still run my application.yml file to load properties.
I wonder if it is possible to run another *.yml
file when running the test case.
Upvotes: 128
Views: 261423
Reputation: 754
I have tested @IlyaSerbis answer and it is working for me. I am using Spring Boot 2.3.
I have tested these scenarios and it worked.
Scenario1 - First I have created an application.yml
file for jUnit purpose and put it under the src/test/resources/config
directory (the same directory as the main application.yml
file) where it completely replaces the original yaml file (not overwrite). That means it will not use any of the properties mentioned in application.yml
of the src/main/resources/config
directory (main directory).
Note: In Scenario1
, the path of application.yml
in main
and test
need to be exactly same. If src/main/resources/config/application.yml
then src/test/resources/config/application.yml
. If src/main/resources/application.yml
then src/test/resources/application.yml
Scenario2 - Then I created the application-test.yml
file instead of the application.yml
file under the src/test/resources/config
directory and using the @ActiveProfiles("test")
annotation, I could see jUnit taking property values from the application-test.yml
file (overwriting application.yml
for common properties) and then taking values from application.yml
as well that are not defined in application-test.yml
.
Upvotes: 3
Reputation: 44685
One option is to work with profiles. Create a file called application-test.yml, move all properties you need for those tests to that file and then add the @ActiveProfiles
annotation to your test class:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest
@ActiveProfiles("test") // Like this
public class MyIntTest{
}
Be aware, it will additionally load the application-test.yml, so all properties that are in application.yml are still going to be applied as well. If you don't want that, either use a profile for those as well, or override them in your application-test.yml.
Upvotes: 149
Reputation: 48753
There are several solutions. The easiest and self-describing is based on spring.config.location
property. @TestPropertySource
has highest precedence, so the property goes there.
Following example demonstrates minimal Spring Boot test:
@ExtendWith(SpringExtension.class)
@ContextConfiguration(initializers = {ConfigDataApplicationContextInitializer.class})
@TestPropertySource(properties = {"spring.config.location=classpath:debug.yml"})
@EnableConfigurationProperties({DataSourceProperties.class})
public class MyTest {
@Autowired DataSourceProperties dbProps;
@Test
public void test() {
System.out.println(dbProps.getUrl());
}
}
ConfigDataApplicationContextInitializer
is hidden when you use @SpringBootTest
. @EnableConfigurationProperties
is here because we slicing execution environment to minimum (no auto-scanning!).
spring.config.location
property overrides default search strategy, like classpath:application.yml
- nice if you want a completely separated config!
spring.config.location
allows to specify a list of locations with comma:
classpath:common.yml,file:./config/local.yml
Some control is possible with spring.config.name
.
Another way is to use @PropertySource(factory = ...)
for YAML files (because Spring Framework only supports XML & .properties
config files):
@PropertySource(value = {"file:./local.yml"}, factory = MyTest.YamlPropertySourceFactory.class)
public class MyTest {
public static class YamlPropertySourceFactory implements PropertySourceFactory {
@Override
public org.springframework.core.env.PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource.getResource());
return new PropertiesPropertySource(resource.getResource().getFilename(), factory.getObject());
}
}
...
}
Upvotes: 1
Reputation: 21081
You can set your test properties in src/test/resources/config/application.yml
file. Spring Boot test cases will take properties from application.yml
file in test directory.
The config
folder is predefined in Spring Boot.
As per documentation:
If you do not like application.properties as the configuration file name, you can switch to another file name by specifying a spring.config.name environment property. You can also refer to an explicit location by using the spring.config.location environment property (which is a comma-separated list of directory locations or file paths). The following example shows how to specify a different file name:
java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
The same works for application.yml
Documentation:
Upvotes: 42
Reputation: 6216
Spring-boot framework allows us to provide YAML files as a replacement for the .properties file and it is convenient.The keys in property files can be provided in YAML format in application.yml file in the resource folder and spring-boot will automatically take it up.Keep in mind that the yaml format has to keep the spaces correct for the value to be read correctly.
You can use the @Value("${property}")
to inject the values from the YAML files.
Also Spring.active.profiles can be given to differentiate between different YAML for different environments for convenient deployment.
For testing purposes, the test YAML file can be named like application-test.yml and placed in the resource folder of the test directory.
If you are specifying the application-test.yml
and provide the spring test profile in the .yml, then you can use the @ActiveProfiles('test')
annotation to direct spring to take the configurations from the application-test.yml that you have specified.
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ApplicationTest.class)
@ActiveProfiles("test")
public class MyTest {
...
}
If you are using JUnit 5 then no need for other annotations as @SpringBootTest already include the springrunner annotation. Keeping a separate main ApplicationTest.class enables us to provide separate configuration classes for tests and we can prevent the default configuration beans from loading by excluding them from a component scan in the test main class. You can also provide the profile to be loaded there.
@SpringBootApplication(exclude=SecurityAutoConfiguration.class)
public class ApplicationTest {
public static void main(String[] args) {
SpringApplication.run(ApplicationTest.class, args);
}
}
Here is the link for Spring documentation regarding the use of YAML instead of .properties
file(s): https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Upvotes: 14
Reputation: 69
Lu55 Option 1 how to...
Add test only application.yml inside a seperated resources folder.
├── main │ ├── java │ └── resources │ ├── application.yml └── test ├── java └── resources └── application.yml
In this project structure the application.yml under main is loaded if the code under main is running, the application.yml under test is used in a test.
To setup this structure add a new Package folder test/recources if not present.
Eclipse right click on your project -> Properties -> Java Build Path -> Source Tab -> (Dialog ont the rigth side) "Add Folder ..."
Inside Source Folder Selection -> mark test -> click on "Create New Folder ..." button -> type "resources" inside the Textfeld -> Click the "Finish" button.
After pushing the "Finisch" button you can see the sourcefolder {projectname}/src/test/recources (new)
Optional: Arrange folder sequence for the Project Explorer view.
Klick on Order and Export Tab mark and move {projectname}/src/test/recources to bottom.
Apply and Close
!!! Clean up Project !!!
Eclipse -> Project -> Clean ...
Now there is a separated yaml for test and the main application.
Upvotes: 2
Reputation: 10693
A simple working configuration using
@TestPropertySource and properties
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
@TestPropertySource(properties = {"spring.config.location=classpath:another.yml"})
public class TestClass {
@Test
public void someTest() {
}
}
Upvotes: 5
Reputation: 1177
This might be considered one of the options. now if you wanted to load a yml file ( which did not get loaded by default on applying the above annotations) the trick is to use
@ContextConfiguration(classes= {...}, initializers={ConfigFileApplicationContextInitializer.class})
Here is a sample code
@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@DirtiesContext
@ContextConfiguration(classes= {DataSourceTestConfig.class}, initializers = {ConfigFileApplicationContextInitializer.class})
public class CustomDateDeserializerTest {
private ObjectMapper objMapper;
@Before
public void setUp() {
objMapper = new ObjectMapper();
}
@Test
public void test_dateDeserialization() {
}
}
Again make sure that the setup config java file - here DataSourceTestConfig.java
contains the following property values.
@Configuration
@ActiveProfiles("test")
@TestPropertySource(properties = { "spring.config.location=classpath:application-test.yml" })
public class DataSourceTestConfig implements EnvironmentAware {
private Environment env;
@Bean
@Profile("test")
public DataSource testDs() {
HikariDataSource ds = new HikariDataSource();
boolean isAutoCommitEnabled = env.getProperty("spring.datasource.hikari.auto-commit") != null ? Boolean.parseBoolean(env.getProperty("spring.datasource.hikari.auto-commit")):false;
ds.setAutoCommit(isAutoCommitEnabled);
// Connection test query is for legacy connections
//ds.setConnectionInitSql(env.getProperty("spring.datasource.hikari.connection-test-query"));
ds.setPoolName(env.getProperty("spring.datasource.hikari.pool-name"));
ds.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
long timeout = env.getProperty("spring.datasource.hikari.idleTimeout") != null ? Long.parseLong(env.getProperty("spring.datasource.hikari.idleTimeout")): 40000;
ds.setIdleTimeout(timeout);
long maxLifeTime = env.getProperty("spring.datasource.hikari.maxLifetime") != null ? Long.parseLong(env.getProperty("spring.datasource.hikari.maxLifetime")): 1800000 ;
ds.setMaxLifetime(maxLifeTime);
ds.setJdbcUrl(env.getProperty("spring.datasource.url"));
ds.setPoolName(env.getProperty("spring.datasource.hikari.pool-name"));
ds.setUsername(env.getProperty("spring.datasource.username"));
ds.setPassword(env.getProperty("spring.datasource.password"));
int poolSize = env.getProperty("spring.datasource.hikari.maximum-pool-size") != null ? Integer.parseInt(env.getProperty("spring.datasource.hikari.maximum-pool-size")): 10;
ds.setMaximumPoolSize(poolSize);
return ds;
}
@Bean
@Profile("test")
public JdbcTemplate testJdbctemplate() {
return new JdbcTemplate(testDs());
}
@Bean
@Profile("test")
public NamedParameterJdbcTemplate testNamedTemplate() {
return new NamedParameterJdbcTemplate(testDs());
}
@Override
public void setEnvironment(Environment environment) {
// TODO Auto-generated method stub
this.env = environment;
}
}
Upvotes: 2
Reputation: 22283
If you need to have production application.yml
completely replaced then put its test version to the same path but in test environment (usually it is src/test/resources/
)
But if you need to override or add some properties then you have few options.
Option 1: put test application.yml
in src/test/resources/config/
directory as @TheKojuEffect suggests in his answer.
Option 2: use profile-specific properties: create say application-test.yml
in your src/test/resources/
folder and:
add @ActiveProfiles
annotation to your test classes:
@SpringBootTest(classes = Application.class)
@ActiveProfiles("test")
public class MyIntTest {
or alternatively set spring.profiles.active
property value in @SpringBootTest
annotation:
@SpringBootTest(
properties = ["spring.profiles.active=test"],
classes = Application.class,
)
public class MyIntTest {
This works not only with @SpringBootTest
but with @JsonTest
, @JdbcTests
, @DataJpaTest
and other slice test annotations as well.
And you can set as many profiles as you want (spring.profiles.active=dev,hsqldb
) - see farther details in documentation on Profiles.
Upvotes: 18
Reputation: 364
Starting with Spring 4.1, We can directly set the property in application.yml using the @TestPropertySource annotation.
@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource(properties = {"yoursection.yourparameter=your_value"})
public MyIntTest
{
//your test methods
}
Just convert your yaml parameters into complete property structure. For example: If content of application.yml is like below
yoursection:
yourparameter:your_value
Then value to go inside the @TestPropertySource will be,
yoursection.yourparameter=your_value
Upvotes: 3
Reputation: 1253
We can use @SpringBootTest annotation which loads the yml file from src\main\java\com...hence when we execute the unit test, all of the properties are already there in the config properties class.
@RunWith(SpringRunner.class)
@SpringBootTest
public class AddressFieldsTest {
@InjectMocks
AddressFieldsValidator addressFieldsValidator;
@Autowired
AddressFieldsConfig addressFieldsConfig;
...........
@Before
public void setUp() throws Exception{
MockitoAnnotations.initMocks(this);
ReflectionTestUtils.setField(addressFieldsValidator,"addressFieldsConfig", addressFieldsConfig);
}
}
We can use @Value annotation if you have few configs or other wise we can use a config properties class. For e.g
@Data
@Component
@RefreshScope
@ConfigurationProperties(prefix = "address.fields.regex")
public class AddressFieldsConfig {
private int firstName;
private int lastName;
.........
Upvotes: 0
Reputation: 9100
You can use @TestPropertySource
to load different properties/yaml file
@TestPropertySource(locations="classpath:test.properties")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class MyIntTest{
}
OR if you want to override only specific properties/yaml you can use
@TestPropertySource(
properties = {
"spring.jpa.hibernate.ddl-auto=validate",
"liquibase.enabled=false"
}
)
Upvotes: 24
Reputation: 1650
See this: Spring @PropertySource using YAML
I think the 3rd answer has what you're looking for, i.e have a separate POJO to map your yaml values into:
@ConfigurationProperties(path="classpath:/appprops.yml", name="db")
public class DbProperties {
private String url;
private String username;
private String password;
...
}
Then annotate your test class with this:
@EnableConfigurationProperties(DbProperties.class)
public class PropertiesUsingService {
@Autowired private DbProperties dbProperties;
}
Upvotes: 5