I'm using JUnit to test my application and everything works fine as long as the database has been initialised before the testing (using gradle bootRun to run as a web-app). However, if the database is empty, the application does not seem to initialise any models or entities before testing. Is there a way I'm supposed to do this? I made an assumption that the ApplicationRunner class will be ran before the test and initalise the entities. Is there a way to do this or am I using the wrong approach?
This is how my application.properties file is looking like:
server.port=8090
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=123456
server.ssl.key-password 123456
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=create
spring.jpa.hibernate.naming-strategy:org.hibernate.cfg.ImprovedNamingStrategy
application.logger.org.springframework=INFO
My database is stored in /src/main/java/application/persistence/DbConfig.java using a DriverManagerDataSource connection. And I have setup ApplicationRunner to run add a few rows to the db upon starting.
edit:
I should also add that these are the annotations I'm using on the JUnit test file:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes={
AdeyTrackApplication.class,
SecurityConfig.class,
WebConfig.class,
AuthorizationController.class
})
There are various options if you do not want to execute that explicitly from #Before JUnit hook.
Use Spring Boot's JDBC initialization feature, where you would place schema.sql or data.sql into src/test/resources folder, so that it would be picked up only during testing.
Use Spring's #Sql annotation
You can use #Sql annotaion for populate your DB, for example^
#Sql(scripts = "classpath:db/populateDB.sql")
The above answers all use the .sql schema loading technique where I'd have to have a .sql schema for tests. I didn't want to do it that way as my schema would be expanding and I'd rather not go through the hassle of adding entries to the schema as my tests expand.
As I'm using Spring Boot, I came across this annotation which seems to solve the issue by first running bootRun and then running the tests.
In my test annotations I replaced the #ContextConfigurations with #SpringApplicationConfiguration and left all the classes to be the same. This seemed to solve the issue. So now the test task invokes bootRun to load the classes and then runs the tests.
See #SpringApplicationConfiguration
Hop this helps anyone facing the same issue.
Related
In my Spring Boot program I'm getting a failure due to a bad property value on load. In particular, it uses the DB2 hibernate dialect but it's not defined in the property file I thought I was using.
Assuming no annotations, where does Spring look for the properties file? Yes I know it normally resides in src/main/resources/application.properties
What if I have a property in my test cases; does it ignore the one in main and use the one in test? Or does it start with the main version and let the test one override the main where it applies?
Does the application profile affect the property file used? Some people use the same application.properties file name in both main and test.
If I do have a TestSource annotation with a class path location, does it still augment it with something somewhere else?
Finally, how can I get Spring to tell me everywhere it looked for properties and not just one of them?
#Woodsman
It's possible to use many settings in each profile/environment in spring application on src/main/resources/ folder
application-dev.properties
application-local.properties
application-onlytests.properties
application-prd.properties
application.properties
the name after hyphen will be the name profile got by spring
Ex: application-{myenviroment}.properties
When you start spring application will be used application.properties by default.
You can tell spring to use an specific properties passing the environment in one of ways below:
Putting spring.profiles.active=prd inside application.properties file
Passing by parameters when start spring app --spring.profiles.active=local
Running your jar on command line java -jar myjar.jar --spring.profiles.active=dev
Setting an environment var in your machine/docker/container SET SPRING_ACTIVES_PROFILE=local
There are other ways using annotations on beans, passing jvm arguments and others
If you need run your tests in a specific configuration ( vars, database, settings ), It's possible to pass which .properties will be used
#ExtendWith(SpringExtension.class)
#AutoConfigureMockMvc
#SpringBootTest
#TestPropertySource(locations = "classpath:application-onlytests.properties")
public class RunTest_from_onlytests_properties {
#Autowired
private MockMvc mockMvc;
#Test // org.junit.jupiter.api.Test
public void test() throws Exception{
// ...
}
}
I try to test my spring boot application via JUnit 5.
The test methods need some environment variables. Even I put them on the list, each test method creates a new JUnit config so I have to put them again.
I saw the document on JetBrains.
I can not save the JUnit config. because each config. depends on the method.
Is there any way to create a permanent JUnit config. on IntelliJ?
You may edit the Junit run configuration in the "Run configuration templates for new projects":
This is a bad idea. Setting up your environment variables in something like IntelliJ will make this unportable or unrunnable in a Jenkins environment.
Because you're using Spring Boot, you have more flexibility than you realize. Rework your code so that the environment variables can be injected in through application properties. Then, you can add the application properties to your test through the #SpringBootTest annotation.
I write integration test for SpringBoot application with opportunity to run multiple tests simultaneously they have file system dependencies that's why I need to create unique root folder for each integration test.
I have a spring bean in production app that have #PostConstruct section to perform long-running operations. These long-running operations rely on file system structure that I prepare in #Before section of unit-tests.
Unique folders for simultaneously running tests are set via root.directory=target/results/#{T(java.util.UUID).randomUUID().toString()}. This property is injected as #Value in spring #Component class to avoid re-calculation root directory in different places.
The main issue is following: I need to prepare folders which name should be specified via application.properties with some resources(copy files, folders) in #Before test-section and run #PostConstruct only after all resource are prepared.
I tried several variants: 1) autowire in the test a bean with #PostConstruct and invoke it programmatically in the end of #Before - it's a single working case and it looks strange and fragile
2) Replace #PostConstruct with InitializingBean and afterPropertiesSet - it doesn't work. Because I have a value for folder name on bean initialization stage but without copied resources that I copy in #Before test section
I hope I explained well. I will be appreciate with any help or advice.
Your Question are bit vague but to answer the issues.
The main issue is following: I need to prepare folders which name should be specified via application.properties with some resources(copy files, folders) in #Before test-section and run #PostConstruct only after all resource are prepared.
Make Sure you are running Test
#RunWith(SpringRunner.class)
#SpringBootTest(properties = "myFileName=test.txt")
In test #Before use
#Rule
public final TemporaryFolder temporaryFolder = new TemporaryFolder();
temporayFolder.newFile( use #Value here)
So #Before will run before any spring boot startup and then call your function in one of the unit test methods
I've started to learn Spring Boot in version 2.1.0 and I made a simple application Controller->Service->Repository->Database(H2). Very, very simple application just to start with Spring Boot.
I've read that in that framework I can add under src/resources a file data.sql where I can define insert/update etc. and after run my application that data will be stored. Everything works ok, but when I wanted to write test for my service, just to check if my repository works ok (I test DB for learning purpose) I see that while I run my test in my DB there are already values from data.sql, but I don't have data.sql under test folder. It is under src.
Maybe someone knows, how to configure project that not to take this data.sql from src/resources? Is it possible? Maybe I have to add some more annotations?
**** EDIT ****
This is my repo:
You can create test application-test.properties in test/resources
and override in in test like this:
#RunWith(SpringRunner.class)
#SpringApplicationConfiguration(classes = ExampleApplication.class)
#TestPropertySource(locations="classpath:test.properties")
public class ExampleApplicationTests {
}
Then in you new created application-test.properties file block running your script:
spring.datasource.initialization-mode=never
I have an integration test set up like:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {XmlFileSplitter.class, ...})
public class XmlFileSplitterTests { ..
In the XmlFileSplitter I have a property that is annotated with #Value("${default.output.file}") and its value is retrieved from the application.properties. This works fine when running the app normally. However when running the integration test, the value is not resolved (it is "${default.output.file}").
When i debugged through the code for resolving the placeholder i noticed the org.springframework.beans.factory.support.AbstractBeanFactory embeddedValueResolvers was empty in the test, while containing a PropertySourcesPlaceholderConfigurer when running the app normally.
I saw the normal run has PropertyPlaceholderAutoConfiguration from spring-boot-autoconfigure to configure the propertyplaceholder and i figured i needed to add this class to the SpringApplicationConfiguration classes to have it configured for the integration test. I added it:
#SpringApplicationConfiguration(classes = {XmlFileSplitter.class, ... , PropertyPlaceholderAutoConfiguration.class})
and it now indeeds resolves the #Value annotation (with value from application.properties).
However this feels wrong, adding knowledge of this class to my test. My question is how to solve this properly?