How to resove java.lang.IllegalArgumentException: Property 'dataSource' in Junit for Springboot Rest - spring-boot

The error is thrown while trying to unit test the Service class that contains an autowired Dao object which internally uses an Autowired JdbcTemplate in Spring boot Rest service using Junit and Mockito

in you `SpringBootTest you should pass config classes or properties files where all configs are.
Probably dataSource is missing
#SpringBootTest(classes = YouAppRunnerOrConfig.class, properties = "...")

Related

#EnableAutoConfiguration(exclude =...) on tests failed in Spring Boot 2.6.0

I tried to upgrade my data-mongo example project to Spring Boot 2.6.0. There is a test designed to run against Testcontainers, I also included the embedded mongo dep for other tests, so I have to exclude the AutoConfiguration for embedded mongo to make sure this test working on Docker/testcontainers.
The following configuration worked well with Spring Boot 2.5.6.
#DataMongoTest
#ContextConfiguration(initializers = {MongodbContainerInitializer.class})
#EnableAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class)
#Slf4j
#ActiveProfiles("test")
public class PostRepositoryTest {}
But after upgrading to Spring Boot 2.6.0 and running the application, I got the exception like this.
[ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: o
rg.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'embeddedMongoServer' defined in class path resource [org/springframework/boot/autoconfig
ure/mongo/embedded/EmbeddedMongoAutoConfiguration.class]: Unsatisfied dependency expressed through method 'embeddedMongoServer' parameter 0; nested exception is org.springframework.bea
ns.factory.BeanCreationException: Error creating bean with name 'embeddedMongoConfiguration' defined in class path resource [org/springframework/boot/autoconfigure/mongo/embedded/Embed
dedMongoAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [de.flap
doodle.embed.mongo.config.MongodConfig]: Factory method 'embeddedMongoConfiguration' threw exception; nested exception is java.lang.IllegalStateException: Set the spring.mongodb.embedd
ed.version property or define your own MongodConfig bean to use embedded MongoDB
Obviously, #EnableAutoConfiguration(exclude =...) did not affect the context in tests when upgrading to Spring Boot 2.6.0.
Update: Temporarily resolved it, see my answer below.
Just add:
#TestPropertySource(properties = "spring.mongodb.embedded.version=3.5.5")
annotation before your Unit Test and it will start working.
#Henning's answer has a good explanation of why you need this.
As of Spring Boot 2.6, the property spring.mongodb.embedded.version must be set to use the auto-configured embedded MongoDB. It's mentioned in the release notes: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.6-Release-Notes#embedded-mongo
This is also what the error message you posted, advises to do: Set the spring.mongodb.embedd ed.version property or define your own MongodConfig bean to use embedded MongoDB
The annotation #DataMongoTest is meta-annotated with #ImportAutoConfiguration and #AutoConfigureDataMongo, and is designed to trigger auto-configuration of MongoDB unless explicitly disabled as you do in the working configuration examples.
In your first configuration example, the annotation #EnableAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class) does not override this effect of #DataMongoTest.
With Spring Boot 2.5.6, the auto-configured MongodConfig bean is most likely also part of the application context but not effectively used. But this depends on the rest of the code and in particular on the MongodbContainerInitializer.
Use #ImportAutoConfiguration(exclude = ...) or #DataMongoTest(excludeAutoConfiguration = ...) on test classes to overcome this barrier when upgrading to Spring Boot 2.6.0.
#DataMongoTest
#ImportAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class)
//other config are ommitted
public class PostRepositoryTest {}
//or
#DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
public class PostRepositoryTest {}

Spring Annotation #WebMvcTest does not work in an app that has Jpa repositories

I have a Spring App that uses JPA repositories (CrudRepository interfaces). When I try to test my controller using the new Spring test syntax #WebMvcTest(MyController.class), it fails coz it tries to instantiate one of my service class that uses JPA Repository, does anyone has any clues on how to fix that? The app works when I run it.
Here is the error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.myapp.service.UserServiceImpl required a bean of type 'com.myapp.repository.UserRepository' that could not be found.
Action:
Consider defining a bean of type 'com.myapp.repository.UserRepository' in your configuration.
According to the doc
Using this annotation will disable full auto-configuration and instead apply only configuration relevant to MVC tests (i.e. #Controller, #ControllerAdvice, #JsonComponent Filter, WebMvcConfigurer and HandlerMethodArgumentResolver beans but not #Component, #Service or #Repository beans).
This annotion only apply on the Spring MVC components.
If you are looking to load your full application configuration and use MockMVC, you should consider #SpringBootTest combined with #AutoConfigureMockMvc rather than this annotation.
I was able to unit test a Rest Controller by implementing junit 5 and using #SpringJUnitConfig along with #WebMvcTest. I am using Spring Boot 2.4.5 and this is my example:
#SpringJUnitConfig
#WebMvcTest(controllers = OrderController.class)
class OrderControllerTest {
#Autowired
private MockMvc mockMvc;
// This is a Mock bean of a Spring Feign client that calls an external Rest Api
#MockBean
private LoginServiceClient loginServiceClient;
// This is a Mock for a class which has several Spring Jpa repositories classes as dependencies
#MockBean
private OrderService orderService;
#DisplayName("should create an order")
#Test
void createOrder() throws Exception {
OrderEntity createdOrder = new OrderEntity("123")
when(orderService.createOrder(any(Order.class))).thenReturn(createdOrder);
mockMvc.perform(post("/api/v1/orders").contentType(MediaType.APPLICATION_JSON).content("{orderId:123}"))
.andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))TODO: here it will go the correlationId
.andExpect(jsonPath("$.orderId").value("123"));
}
}
Please only use #SpringBootTest when you are implementing integration tests.
I faced this same problem. Using #SpringBootTest and #AutoConfigureMockMvc worked perfectly for me.

Spring Boot Scanning Classes from jars issue

In my sample spring boot application, i have added a dependency of a custom jar. My sample application has a support for web and jpa.
The jar which i've created contains a Spring MVC controller. Below is the sample code
#Controller
public class StartStopDefaultMessageListenerContainerController {
#Autowired(required=false)
private Map<String, DefaultMessageListenerContainer> messageListeners;
I haven't manually created a bean instance of this controller anywhere in my code.
Problem - When i start my spring boot application by running the main class, i get an error in console that prob while autowiring DefaultMessageListenerContainer.
My question here is, even though this class StartStopDefaultMessageListenerContainerController is just present in the classpath, it's bean shouldn't be created and autowiring should not happen. But spring boot is scanning the class automatically and then it tries to autowire the fields.
Is this the normal behavior of spring and is there anyway i can avoid this?
If the StartStopDefaultMessageListenerContainerController class is part of component scanning by spring container, Yes spring tries to instantiate and resolve all dependencies.
Here your problem is #Autowired on collection. Spring docs says,
Beans that are themselves defined as a collection or map type cannot be injected through #Autowired, because type matching is not properly applicable to them. Use #Resource for such beans, referring to the specific collection or map bean by unique name.
And also Refer inject-empty-map-via-spring

Mockito Spring 3.1 Integration

I have been using #Configuration support in Spring to create my Mockito Mocks for use in JUnit tests
#Configuration
public class MockAppContextHelper {
#Bean
public IntegrationServerServiceWrapper integrationServerServiceWrapperTest() {
return mock(IntegrationServerServiceWrapper.class);
}
}
This used to work fine in Spring 3.0.2.
In Spring 3.1 I get the following error:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'integrationServerServiceWrapperTest' defined in class path resource [com/kn/bpa/task/service/impl/MockAppContextHelper.class]: No matching factory method found: factory bean 'mockAppContextHelper'; factory method 'integrationServerServiceWrapperTest()'. Check that a method with the specified name exists and that it is non-static.
Any ideas?
Thanks for your support
Consider adding a reproduction project per the instructions at https://github.com/SpringSource/spring-framework-issues#readme that demonstrates the configuration in question working in 3.0.2 and failing against 3.1.x

I've injected HttpServletRequest into a bean. How do I unit test it?

I have a bean in which I've injected an HttpServletRequest using the #Autowired annotation.
This injection works correctly when the application context is a web application Context. That's not the case for application contexts for JUnit tests with Spring.
How can I test this bean ? Maybe I can mock an http request, but then how to inject this mock in the bean ?
This is on Spring 3.0 and Junit 4.4
Create a bean of type MockHttpServletRequest and add it to your test context. This should then be autowired into your target bean.

Resources