Spring JUnit5 test not loading resource values - java

I know there are a lot of questions regarding this, but all of them are suggesting to use #TestPropertySource and #EnableConfigurationProperties. I have already used them but still not working.
Config class - src/main/java/com/demo/config/AppConfig.java
#Configuration
#ConfigurationProperties(prefix = "api")
#Getter
#Setter
public class AppConfig {
private List<String> providers;
private boolean enabled;
}
Property source - src/test/resources/application-test.yml
api:
enabled: true
providers:
- prov1
- prov2
Test class - src/test/../MyTest.java
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = MyTestConfiguration.class)
class MyTest {
#Autowired
private AppConfig appConfig;
#Test
void runTest() {//some code with breakpoint}
}
Test configuraton - src/test/.../MyTestConfiguration.java
#TestConfiguration
#TestPropertySource(locations = "classpath:application-test.yml")
#EnableConfigurationProperties(value = AppConfig.class)
#ActiveProfiles("test")
public class MyTestConfiguration {
}
When I run the test, runTest() and inspect autowired appConfig value, the providers are empty and enabled is false. That means the values in yml file were not loaded.
I found a similar kind of question, but without answer.

I modified MyTest as #sergey-tsypanov suggested and then deleted MyTestConfiguration class. It worked and appConfig has values.
#SpringBootTest(classes = AppConfig.class)
#EnableAutoConfiguration
#ActiveProfiles("test")
class MyTest {
#Autowired
private AppConfig appConfig;
#Test
void runTest() {//some code with breakpoint}
}
It seems even if I don't have #SpringBootApplication, I can use #SpringBootTest and #EnableAutoConfiguration. I had spring Boot dependency in pom.xml

I think you need to replace
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = MyTestConfiguration.class)
with
#SpringBootTest(classes = {MyTestConfiguration.class})
Then application-test.yml will be picked up automatically.

Related

How to load values from properties using Configuration class and use it in test classes?

Below is my #Configuration class that loads the properties from application.yml:
#Configuration
public class MyConfiguration {
#Bean(name = "products")
#ConfigurationProperties(prefix = "sale.clearance")
public Map<String,String> products() { return new HashMap<>() ;
}
I am writing a Junit test class. Below is the snippet of the test class:
#RunWith(SpringRunner.class)
#ExtendWith({SpringExtension.class,MockitoExtension.class})
#SpringBootTest
#ActivePRofiles("test")
#ContextConfiguration(classes = MyConfiguration.class)
public class MyControllerTest {
#Resource(name = "products")
public Map<String,String> products;
#Mock
SomeService someService;
...
...
}
The products map is still showing as null.
I don't want to mock the object for products map. Instead I want to use a similar configuration class to load from the yml file. How can I achieve it? Should I write a new test configuration class?
I think you should use application—test.yml,You can check activeProfileusage

SpringBoot #WebMvcTest is loading non-dependent beans when #ComponentScan is used along with #SpringBootApplication

I am using SpringBoot 2.3.3.RELEASE and I have following web controllers and Services.
myapp
- controllers
- ProductController
- OrderController
- services
- ProductService
- OrderService
ProductController only depends on ProductService and OrderController only depends on OrderService.
Following is my SpringBoot main entrypoint class:
package com.sivalabs.myapp;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I have an #WebMvcTest controller for testing ProductController as follows:
#WebMvcTest(controllers = ProductController.class)
class ProductControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private ProductService productService;
//some tests
}
Everything works perfectly fine with this configuration.
I am trying to use some external library with Spring components which has different package name, so I want to override #ComponentScan as follows:
package com.sivalabs.myapp;
import com.somelib.BeanConfig;
#SpringBootApplication
#ComponentScan(basePackageClasses = {Application.class, BeanConfig.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
When I include #ComponentScan on my main entrypoint class and run my #WebMvcTest based test ProductControllerTest then in addition to ProductService SpringBoot is trying to initialise OrderService also. Ideally ProductControllerTest should not load OrderService as ProductController doesn't depend on OrderService. Is it a bug?
Workarounds:
If I use #ComponentScan the way it is used on #SpringBootApplication meta-annotation and include basePackageClasses it is working fine.
package com.sivalabs.myapp;
#SpringBootApplication
#ComponentScan(excludeFilters = { #Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), #Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) },
basePackageClasses = {Application.class, BeanConfig.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Instead of adding #ComponentScan on main entrypoint class if I add another configuration class and add #ComponentScan on that class then it's working fine.
package com.sivalabs.myapp.config;
#Configuration
#ComponentScan(basePackageClasses = {BeanConfig.class})
public class AppConfig {
}
Is it a bug in component scanning process or is it working as expected?
It working as expected.
#SpringBootAplication already have #ComponentScan with filters, and redeclare it as in workaroud #1 doesn't make sense, right?
Problem With original code is that #ComponentScan overrides exclude filters applied inside #SpringBootApplocation annotation. And stuff is not excluded, so when #WebMvc tries to request part of context using filters it fails, and entire context is loaded.
Just check what beans are initialized for context in each scenario. And stick to solution 2. #SpringBootTest will scan packages where application class is places, and any additional packages should be scanned by configurations. That is even more flixible right? :)

Spring Boot 2.1 : Not loading property from application-test.yml

I am trying to read a property from application-test.yml during my unit test execution, but instead, the property from application-dev.yml is being read instead. I do not have a application.yml file. Appreciate the help.
AppProperties.java
#Component
#ConfigurationProperties(prefix="app")
public class AppProperties {
private String test;
public String getTest() {
return this.test;
}
public void setTest(String test) {
this.test = test;
}
}
application-dev.yml
spring:
profiles: dev
application:
name: testApplication
app:
test: 1
application-test.yml
spring:
profiles: test
application:
name: testApplication
app:
test: 2
AppServiceTest.java
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {AppProperties.class}, initializers= ConfigFileApplicationContextInitializer.class)
#EnableConfigurationProperties
#ActiveProfiles("test")
public class AppServiceTest{
#Autowired
AppProperties appProperties;
#Test
public void test(){
appProperties.getTest();
//This returns "1" instead of the desired "2"
}
Use #SpringBootTest annotation on unit test class
Spring Boot provides a #SpringBootTest annotation, which can be used as an alternative to the standard spring-test #ContextConfiguration annotation when you need Spring Boot features. The annotation works by creating the ApplicationContext used in your tests through SpringApplication. In addition to #SpringBootTest a number of other annotations are also provided for testing more specific slices of an application.
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {AppProperties.class}, initializers=
ConfigFileApplicationContextInitializer.class)
#EnableConfigurationProperties
#SpringBootTest
#ActiveProfiles("test")
public class AppServiceTest{
#Autowired
AppProperties appProperties;
#Test
public void test(){
appProperties.getTest();
//This returns "1" instead of the desired "2"
}

Unit testing with SpringJUnit4ClassRunner using only #Component and #Autowired

I have the following class:
#Component
public class MyClass {
#Autowired MyPojo pojo;
}
How do i test it without mocking the injected beans? I do not have a configuration [XML or declarative].
I have done the following:
#RunWith(SpringJUnit4ClassRunner.class)
#ComponentScan
public class MyClassTest {
#Autowired MyClass myClass;
#Test
public void test() {
this.myClass...()
}
}
If you do not want use any type of configuration, neither Java nor XML config, you can use #ContextConfiguration with your component classes listed:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { MyPojo.class, MyClass.class })
public class MyClassTest {
#Autowired
private MyClass myClass;
#Test
public void test() {
// myClass...
}
}
Please note that MyPojo class should also be annotated with #Component.
However, in the real life scenario you probably will need at least one #Configuration class (which can be also used with #ContextConfiguration).
Please refer Spring Documentation for more information about Spring integration tests support.

junit spring boot profile properties not being read

I am trring to read a value from the properties file in my junit setup using spring boot.
I can not read the value. Below is my content:-
application-test.properties
my.user.name=Amar
COnfig file to create beans:
#Configuration
#ActiveProfiles("test")
#Profile("test")
public class RdbmsTestConfig {
#Value("${my.user.name}")
private String name;
#Bean
public String myString(){
return "Amar";
}
#Bean
public PropsHolder propsHolder() {
PropsHolder propsHolder = new PropsHolder();
propsHolder.setUserName(name);
return propsHolder;
}
}
My test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = RdbmsTestConfig.class)
#ActiveProfiles("test")
public class TestRoomService {
#Autowired
#Qualifier("myString")
private String myString;
#Autowired
private PropsHolder propsHolder;
#Autowired
private Environment env;
#Test
public void userTest() {
Arrays.stream(env.getActiveProfiles()).forEach(System.out::println);
System.out.println(propsHolder.getUserName());
Assert.assertNotNull(myString);
Assert.assertEquals("Amar",myString);
}
}
The value for propsHolder.getUserName comes out to be ${my.user.name}
First remove #ActiveProfiles("test") from your class RdbmsTestConfig. Then your test just defines the RdbmsTestConfig as spring context. As I can see you do not run a real spring boot test. The problem is you do not have any PropertyPlaceholderConfigurer configured in your spring config. So either configure one PropertyPlaceholderConfigurer or add #SpringBootTest to your test if you have any SpringBootApplication.
I've never used #Profile(), so i'm not sure if that is supposed to do what you want it to do. But I'm always using #PropertySources(), because otherwise, how is the code supposed to know where to look for the properties?
#Configuration
#PropertySources(value = { #PropertySource("classpath:core-
test.properties") })
I created a base test class that has the required annotations:-
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = RdbmsTestConfig.class)
#ActiveProfiles("test")
#SpringBootTest
public abstract class BastTest { }
#ActiveProfiles set the profile to use used, I dont have to mention it in the application.properties file
My test class now extends this:-
public class TestRoomService extends BastTest
In my RdbmsTestConfig remove #ActiveProfiles annotation.

Categories