#Value "Could not resolve placeholder" in Spring Boot Test - java

I want to take a Junit test for Spring-boot as below:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {ApplicationTest.class})
public class TestOnSpring {
#Value("${app.name}")
private String appName;
#Test
public void testValue(){
System.out.println(appName);
}
}
and ApplicationTest.java like this
#ComponentScan("org.nerve.jiepu")
#EnableAutoConfiguration()
public class ApplicationTest {
public static void main(String[] args) {
SpringApplication.run(ApplicationTest.class, args);
}
}
and my POM like this:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.0.BUILD-SNAPSHOT</version>
</parent>
When I run the test, I got below error information
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'app.name' in string value "${app.name}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:204)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:178)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:807)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1027)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:543)
... 31 more
But When I run this application as normal Java Application
#SpringBootApplication
public class Application {
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
}
It work well!
What's wrong with it ? How should I take the junit test with Spring-boot?
Thanks a lot!

You need to add
#PropertySource("classpath:application.properties")
to your class, so it will pick your normal configurations.
If you need different configurations for test you can add
#TestPropertySource(locations="classpath:test.properties")
If not just copy paste your config file to test/resources folder, then boot will pick from there.
See this.

You can use the #SpringBootTest that will do create the PropertySourcesPlaceholderConfigurer automatically.
This is described in the Testing chapter of the Spring Boot documentation.
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-configfileapplicationcontextinitializer-test-utility

You have annotated your test class with #ContextConfiguration(classes = {ApplicationTest.class}). Wherein ApplicationTest.class does the component scan on a mentioned package. When you run your test it tries to find the configuration from the resources folder in 'main' instead of 'test'. If you annotate your class with #SpringBootTest(classes = {ClassToBeTested.class}) or just #SpringBootTest in this particular case, I think (not 100% sure) it will create a limited context and pick up the properties from test/resources.
If your properties are test specific, you can name your properties/yml file as application-test.properties or application-test.yml. And use #ActiveProfiles("test") in your test class so that it will always read test specific properties file.
I usually use this solution which works for me.

For me the issue was related to the profile set for the application properties.
application.yml:
spring:
config:
activate:
on-profile: local
mongodb:
uri: mongodb+srv:/
Class with reference to value:
#Value("${mongodb.uri}")
private String uri;
Resolution in test class method:
#SpringBootTest
#ActiveProfiles("local")
class myTestClass {

Related

Passing TestPropertySource location has no affect

I am trying to pass a test.properties file to the #TestPropertySource annotation like so:
#SpringBootTest
#TestPropertySource(locations = "classpath:test.properties")
public class ApplicationTests {
#Test
public void contextLoads() {
}
#Test
public void main() {
Application.main(new String[] {});
}
}
I then call the main application, hoping that test.properties will be taken. The Application.main is a standard Boot application:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Perhaps I have misunderstood the intended purpose of #TestPropertySource?
Thanks for any help
The following is written in the documentation:
#TestPropertySource is a class-level annotation that is used to
configure the locations() of properties files and inlined properties()
to be added to the Environment's set of PropertySources for an
ApplicationContext for integration tests.
So basically, test property sources can be used to selectively override properties
defined in system and application property source.
If #TestPropertySource is declared as an empty annotation (i.e., without explicit values for locations() or properties()), an attempt will be made to detect a default properties file relative to the class that declared the annotation. For example, if the annotated test class is com.example.MyTest, the corresponding default properties file is "classpath:com/example/MyTest.properties". If the default cannot be detected, an IllegalStateException will be thrown.
In your case, file test.properties should be placed in resources folder.
You can check this example to see how it works in action.

Read #PropertySource without Spring Boot Application

I have a multi module Spring Boot project with the following structure:
MyAppModule
src/main/java/Application.java
...
IntegrationTests
src/test/java/integrationTest.java
The IntegrationTest module is testing the MyAppModule. The IntegrationTest module does not have a main package. Therefore there is no Spring Application. It has just the test package.
Nevertheless I would like to read in the application.yaml for some properties but I'm not able to because the attributes are always null:
#Configuration
#PropertySource("classpath:application.yaml")
public class IntegrationTest {
#Value("${app.url}")
private String appUrl;
}
Isn't it possible to use the #Value annotation without having a Spring Application (main with SpringApplication.run etc.)?
Why not just #ConfigurationProperties?
#Configuration
#ConfigurationProperties(prefix = "app")
public class IntegrationTest {
private String url;
}
Add Integration tests base package for component scanning in spring configuration.
#ComponentScan("basePackage1,basePackage2....etc")
Thanks for all responses. Solved it with the following code and a SpringBootApplication was necessary.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class IntegrationTest {
#Value("${app.url}")
private String url;
}

ServletContext cannot open properties file when executing JUnit test

I'm testing a REST controller using JUnit 4 and MockMvc. When I've written the test a few weeks ago, everything worked as expected. I've done some modifications in my code but I didn't change the JUnit test. Now, when I'm trying to run my tests, I have the error:
Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/application.properties]
Here is my code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = MyServerApplication.class)
#SpringBootTest
#Transactional
public class MovieControllerTest {
private MockMvc mockMvc;
#Autowired
private MovieRepository movieRepository;
#Autowired
private WebApplicationContext wac;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
// Some tests
}
And my main class:
#SpringBootApplication
public class MyServerApplication{
public static void main(String[] args) {
SpringApplication.run(MyServerApplication.class, args);
}
}
My application.properties file is located in src/main/resources. I didn't move this file, I didn't do anything but add some code in my services and add some properties in my file.
I read SO questions & doc, and tried these solutions:
Check that src/main/resources is still in my test classpath
Add #PropertySource("classpath:application.properties") under the annotations in my test ; it didn't work so I tried to create a src/test/resources with a copy of application.properties inside, as suggested in one post
Add #PropertySource("classpath:application.properties") in the main class instead of the test class
Add #WebAppConfiguration annotation
Add #WebMvcTest annotation
I didn't try all of these solutions at the same time of course, I removed the added code after each failure.
I can still run my code without any issue though, only the test class results in FileNotFoundException.
How to solve this? And why do I have an issue with the test class but everything working fine when I run my server?
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = MyServerApplication.class)
#SpringBootTest
#Transactional
public class MovieControllerTest { ... }
This is what you have on your test class. When using #SpringBootTest you shouldn't be using #ContextConfiguration (see testing chapter of the Spring Boot Reference Guide).
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
#Transactional
public class MovieControllerTest { ... }
I would also suggest you use Spring Boot for testing instead of trying to do things manually. For mock mvc testing Spring Boot applications there are special slices and setup already done for you.
To enable this add #AutoConfigureMockMvc to your test and put #Autowired on the MockMvc field (and remove the setup in your #Before method).

Unable to find a #SpringBootConfiguration when doing a JpaTest

I'm trying to run a simple Junit test to see if my CrudRepositories are indeed working.
The error I keep getting is:
Unable to find a #SpringBootConfiguration, you need to use #ContextConfiguration or #SpringBootTest(classes=...) with your test
java.lang.IllegalStateException
Doesn't Spring Boot configure itself?
My Test Class:
#RunWith(SpringRunner.class)
#DataJpaTest
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class JpaTest {
#Autowired
private AccountRepository repository;
#After
public void clearDb(){
repository.deleteAll();
}
#Test
public void createAccount(){
long id = 12;
Account u = new Account(id,"Tim Viz");
repository.save(u);
assertEquals(repository.findOne(id),u);
}
#Test
public void findAccountByUsername(){
long id = 12;
String username = "Tim Viz";
Account u = new Account(id,username);
repository.save(u);
assertEquals(repository.findByUsername(username),u);
}
My Spring Boot application starter:
#SpringBootApplication
#EnableJpaRepositories(basePackages = {"domain.repositories"})
#ComponentScan(basePackages = {"controllers","domain"})
#EnableWebMvc
#PropertySources(value {#PropertySource("classpath:application.properties")})
#EntityScan(basePackages={"domain"})
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
My Repository:
public interface AccountRepository extends CrudRepository<Account,Long> {
public Account findByUsername(String username);
}
}
Indeed, Spring Boot does set itself up for the most part. You can probably already get rid of a lot of the code you posted, especially in Application.
I wish you had included the package names of all your classes, or at least the ones for Application and JpaTest. The thing about #DataJpaTest and a few other annotations is that they look for a #SpringBootConfiguration annotation in the current package, and if they cannot find it there, they traverse the package hierarchy until they find it.
For example, if the fully qualified name for your test class was com.example.test.JpaTest and the one for your application was com.example.Application, then your test class would be able to find the #SpringBootApplication (and therein, the #SpringBootConfiguration).
If the application resided in a different branch of the package hierarchy, however, like com.example.application.Application, it would not find it.
Example
Consider the following Maven project:
my-test-project
+--pom.xml
+--src
+--main
+--com
+--example
+--Application.java
+--test
+--com
+--example
+--test
+--JpaTest.java
And then the following content in Application.java:
package com.example;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Followed by the contents of JpaTest.java:
package com.example.test;
#RunWith(SpringRunner.class)
#DataJpaTest
public class JpaTest {
#Test
public void testDummy() {
}
}
Everything should be working. If you create a new folder inside src/main/com/example called app, and then put your Application.java inside it (and update the package declaration inside the file), running the test will give you the following error:
java.lang.IllegalStateException: Unable to find a #SpringBootConfiguration, you need to use #ContextConfiguration or #SpringBootTest(classes=...) with your test
Configuration is attached to the application class, so the following will set up everything correctly:
#SpringBootTest(classes = Application.class)
Example from the JHipster project here.
It is worth to check if you have refactored package name of your main class annotated with #SpringBootApplication. In that case the testcase should be in an appropriate package otherwise it will be looking for it in the older package . this was the case for me.
It work fo me
the package name of the above test class is changed to the same as the package name of the normal class.
change to this
In addition to what Thomas Kåsene said, you can also add
#SpringBootTest(classes=com.package.path.class)
to the test annotation to specify where it should look for the other class if you didn't want to refactor your file hierarchy. This is what the error message hints at by saying:
Unable to find a #SpringBootConfiguration, you need to use
#ContextConfiguration or #SpringBootTest(classes=...) ...
In my case the packages were different between the Application and Test classes
package com.example.abc;
...
#SpringBootApplication
public class ProducerApplication {
and
package com.example.abc_etc;
...
#RunWith(SpringRunner.class)
#SpringBootTest
public class ProducerApplicationTest {
After making them agree the tests ran correctly.
I had the same issue and I solved by adding an empty class annotated with SpringBootApplication in the root package of the folder src/test/java
package org.enricogiurin.core;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class CoreTestConfiguration {}
The test slice provided in Spring Boot 1.4 brought feature oriented test capabilities.
For example,
#JsonTest provides a simple Jackson environment to test the json serialization and deserialization.
#WebMvcTest provides a mock web environment, it can specify the controller class for test and inject the MockMvc in the test.
#WebMvcTest(PostController.class)
public class PostControllerMvcTest{
#Inject MockMvc mockMvc;
}
#DataJpaTest will prepare an embedded database and provides basic JPA environment for the test.
#RestClientTest provides REST client environment for the test, esp the RestTemplateBuilder etc.
These annotations are not composed with SpringBootTest, they are combined with a series of AutoconfigureXXX and a #TypeExcludesFilter annotations.
Have a look at #DataJpaTest.
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Inherited
#BootstrapWith(SpringBootTestContextBootstrapper.class)
#OverrideAutoConfiguration(enabled = false)
#TypeExcludeFilters(DataJpaTypeExcludeFilter.class)
#Transactional
#AutoConfigureCache
#AutoConfigureDataJpa
#AutoConfigureTestDatabase
#AutoConfigureTestEntityManager
#ImportAutoConfiguration
public #interface DataJpaTest {}
You can add your #AutoconfigureXXX annotation to override the default config.
#AutoConfigureTestDatabase(replace=NONE)
#DataJpaTest
public class TestClass{
}
Let's have a look at your problem,
Do not mix #DataJpaTest and #SpringBootTest, as said above #DataJpaTest will build the configuration in its own way(eg. by default, it will try to prepare an embedded H2 instead) from the application configuration inheritance. #DataJpaTest is designated for test slice.
If you want to customize the configuration of #DataJpaTest, please read this official blog entry from Spring.io for this topic,(a little tedious).
Split the configurations in Application into smaller configurations by features, such as WebConfig, DataJpaConfig etc. A full featured configuration(mixed web, data, security etc) also caused your test slice based tests to be failed. Check the test samples in my sample.
In my case
Make sure your (test package name) of YourApplicationTests is equivalent to the (main package name).
When all the classes were in same package, test classes were working. As soon as I moved all the java classes to different package to maintain proper project structure I was getting the same error.
I solved it by providing my main class name in the test class like below.
#SpringBootTest(classes=JunitBasicsApplication.class)
I think that the best solution for this issue is to align your tests folders structure with the application folder structure.
I had the same issue which was caused by duplicating my project from a different folder structure project.
if your test project and your application project will have the same structure you will not be required to add any special annotations to your tests classes and everything will work as is.
Make sure the test class is in a sub-package of your main spring boot class
This is more the the error itself, not answering the original question:
We were migrating from java 8 to java 11. Application compiled successfully, but the errors Unable to find a #SpringBootConfiguration started to appear in the integration tests when ran from command line using maven (from IntelliJ it worked).
It appeared that maven-failsafe-plugin stopped seeing the classes on classpath, we fixed that by telling failsafe plugin to include the classes manually:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<additionalClasspathElements>
<additionalClasspathElement>${basedir}/target/classes</additionalClasspathElement>
</additionalClasspathElements>
</configuration>
...
</plugin>
In my case I was using the Test class from wrong package.
when I replaced import org.junit.Test; with import org.junit.jupiter.api.Test; it worked.
None of the suggested solutions worked because I don't have #SpringBootApplication in the system. But I figured it out - this is how I fixed:
// AppConfig.java
#Configuration
#ComponentScan("foo")
#ConfigurationPropertiesScan
public class AppConfig {
// ...
}
// HelloWorld.java
#Service
public class HelloWorld {
public void foo() {
// ...
}
}
// HelloWorldTest.java
#SpringBootTest(classes = { AppConfig.class, HelloWorld.class })
public class HelloWorldTest {
#Autowired private HelloWorld helloWorld;
#Test
public testFoo() {
this.helloWorld.foo(); // Testing logic
}
}
The key is including both AppConfig.class and HelloWorld.class in #SpringBootTest.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureWebMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#DataJpaTest
#SpringBootTest
#AutoConfigureWebMvc
public class RepoTest {
#Autowired
private ThingShiftDetailsRepository thingShiftDetailsRepo;
#Test
public void findThingShiftDetails() {
ShiftDetails details = new ShiftDetails();
details.setThingId(1);
thingShiftDetailsRepo.save(details);
ShiftDetails dbDetails = thingShiftDetailsRepo.findByThingId(1);
System.out.println(dbDetails);
}
}
Above annotations worked well for me. I am using spring boot with JPA.

Override application.properties for integration tests in spring-boot app

I have a standard spring-boot app and I want to use MS SQL database for the production environment, whereas for integration tests I'd like to use h2 databse. The problem is that I wasn't able to find out, how to override the default application.properties file. Even though I was trying to follow some tutorials, I didn't come up with the right solution...maybe I'm just missing something...
The main class:
#SpringBootApplication
#EnableTransactionManagement
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication .class, args);
}
}
and the class with tests:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = MyApplication.class)
#WebIntegrationTest
public class MessageControllerTest {
#Autowired
MessageRepository messageRepository;
...
...
...
#Test
public void testSomething(){
...
...
...
...
}
}
So the question is, how to force the spring-boot to use application-test.properties file when running the tests, instead of application.properties, which should be used during the run time.
I tried for example to replace #WebIntegrationTest annotation with #TestPropertySource(locations="classpath:application-test.properties"), but this results in java.lang.IllegalStateException: Failed to load ApplicationContext.
Assuming you have a application-test.properties file in your app.
I do it in two ways :
1.CLI JVM Args
mvn spring-boot:run -Drun.jvmArguments="-Dspring.profiles.active=test
add the application-test.properties as an active profile.
add the spring.profiles.active=test in the application.properties and it will load your application-test.properties file.
As you pointed to in your answer annotate a class test with a specific active profile ( which is not suitable when having a large test classes i think ) #ActiveProfiles("test")
Actually it was pretty easy...after several hours of trying, I've realized that I just needed to annotate my test class with #ActiveProfiles("test") annotation.
#ActiveProfiles("test")
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = MyApplication.class)
#WebIntegrationTest
public class MessageControllerTest {
#Autowired
MessageRepository messageRepository;
...
...
...
#Test
public void testSomething(){
...
...
...
...
}
}

Categories