how to disable autoconfiguration in integration test? - spring

I am trying this:
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
)
#EnableAutoConfiguration(
exclude = [
ReactiveOAuth2ClientAutoConfiguration::class,
ReactiveOAuth2ResourceServerAutoConfiguration::class,
]
)
#ActiveProfiles("testcontainers")
internal class RecordIntegrationTest {
#Test
fun contextLoads() {}
}
With testcontainers profile in application.yml:
spring:
config.activate.on-profile: testcontainers
r2dbc.url: r2dbc:tc:postgresql:///databasename?TC_IMAGE_TAG=13.2
flyway:
enabled: false
But then it tries to create repositories twice (and potentially other beans as well):
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'recordRepository' defined in com.example.RecordRepository defined in #EnableR2dbcRepositories declared on R2dbcRepositoriesAutoConfigureRegistrar.EnableR2dbcRepositoriesConfiguration: Cannot register bean definition [Root bean: class [org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in com.example.RecordRepository defined in #EnableR2dbcRepositories declared on R2dbcRepositoriesAutoConfigureRegistrar.EnableR2dbcRepositoriesConfiguration] for bean 'recordRepository': There is already [Root bean: class [org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in com.example.RecordRepository defined in #EnableR2dbcRepositories declared on R2dbcRepositoriesAutoConfigureRegistrar.EnableR2dbcRepositoriesConfiguration] bound.
UPDATE
Found out that the test runs fine when I move it to the root package
src/test/kotlin/com/example/backend
But it fails when I put it in the package
`src/test/kotlin/com/example/backend/subfolder`
UPDATE 2
I figured out that if a repository defined under src/main/kotlin is in the same package as the integration test that exception shows up.
E.g.:
data class X(#Id id: Long? = null)
// src/main/kotlin/com/example/x/XRepository.kt
interface XRepository : CoroutineCrudRepository<X, Long> {}
This test fails with the above exception:
// src/test/kotlin/com/example/x/XIntegrationTest.kt
#SpringBootTest(classes = [BackendApplication::class])
#EnableAutoConfiguration(
exclude = [
ReactiveOAuth2ClientAutoConfiguration::class,
ReactiveOAuth2ResourceServerAutoConfiguration::class,
]
)
#ActiveProfiles("testcontainers")
internal class XIntegrationTest {
#Test
fun contextLoads() {
}
}
Deleting the repository or moving the integration test to a different package works fine.

Include DataSourceAutoConfiguration in exclude block used by EnableR2dbcRepositories which disables the checking of datasource while starting up your integration test which is used by Repositories or you can configure the datasource to fix this issue.
The issue is basically due to the unavailability of datasource required by the repositories

Somewhere in your src/main/java you have a class that brings the annotation #EnableAutoConfiguration. This is the class that you want to exclude from your tests, when you have defined your own #EnableAutoConfiguration in some other class in test package.

Related

Not able to execute DataJpaTest

I have a spring-data-jpa repository called TagRepository. My spring-boot version is 2.1.2. I am using H2 dependency with runtime scope and I intend to use it for both the application and integration testing. I want to write a DataJpaTest for the TagRepository. I have written the following code:
#RunWith(SpringRunner.class)
#EnableAutoConfiguration
#DataJpaTest
#ContextConfiguration(classes={TagRepository.class})
public class TagRepositoryTest {
#Autowired
private TestEntityManager testEntityManager;
#Autowired
private TagRepository tagRepository;
#Test
public void findByTagTest() {
Tag tag = new Tag("java");
testEntityManager.persistAndFlush(tag);
Optional<Tag> optionalTag = tagRepository.findByTag(tag.getTag());
if(!optionalTag.isPresent()) {
fail("Tag not found hence test failed");
}
assertThat(optionalTag.get()).isEqualTo(tag);
}
}
However, when I execute the test it says Application failed to start and I get following error:
Invalid bean definition with name 'tagRepository' defined in null: Cannot register bean definition [Root bean: class [org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] for bean 'tagRepository': There is already [Generic bean: class [com.upday.task.repository.TagRepository]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] bound.
The bean 'tagRepository', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
The test class itself resides in a different package than jpa repository.
Just remove
#ContextConfiguration(classes={TagRepository.class})
from your test.
It is meant for passing a custom #Configuration not a regular bean.
UPD:
When data jpa test and the repository under test resides in a different packages spring runner needed a little hint to scan classes from another place. Pointing out the application class via
#ContextConfiguration(classes={SpringBootApplication.class})
will extend the component scan scope and allow test environment to pick up additional beans.

Registering test bean with same name in Spring Framework 5.1 [duplicate]

This question already has answers here:
SpringBoot - BeanDefinitionOverrideException: Invalid bean definition
(8 answers)
Closed 3 years ago.
I'm having following config in my production files:
#Configuration
internal class Config {
#Bean
fun clock() = Clock.systemUTC()
}
In tests:
#Configuration
class ClockTestConfiguration {
#Bean
fun clock() = SetableClock()
}
My test annotations:
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = [
MyApplication::class,
ClockTestConfiguration::class
]
)
class MyTest {
...
When I was using Spring Boot 2.0.5.RELEASE it worked like a charm. After upgrading to 2.1.0.RELEASE it fails during bean registration.
Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'clock' defined in com.foo.clock.ClockTestConfiguration:
Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=clockTestConfiguration; factoryMethodName=clock; initMethodName=null; destroyMethodName=(inferred);
defined in com.foo.clock.ClockTestConfiguration] for bean 'clock': There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=config; factoryMethodName=clock; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/foo/clock/Config.class]] bound.
at org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(DefaultListableBeanFactory.java:894)
Is there a clean way to override such bean?
You could use the properties attribute of #SpringBootTest to set spring.main.allow-bean-definition-overriding=true.

springboot project with multiple module and multiple main class -unit test failing

I am trying to write unit test cases for an existing application with multiple module having main classes in each of them. There are more than one class having \#SpringBootApplication. I have written a simple test case which is failing with following error. How can I continue with my test case for one of them.
java.lang.IllegalStateException: Found multiple
#SpringBootConfiguration annotated classes [Generic bean: class
[com.marketshare.ReportingMainClass]; scope=; abstract=false;
lazyInit=false; autowireMode=0; dependencyCheck=0;
autowireCandidate=true; primary=false; factoryBeanName=null;
factoryMethodName=null; initMethodName=null; destroyMethodName=null;
defined in file [C:\My
Data\workspace\services2\microservices\Reporting-Microservice\build\classes\java\main\com\marketshare\ReportingMainClass.class],
Generic bean: class [com.marketshare.SharedMain]; scope=;
abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0;
autowireCandidate=true; primary=false; factoryBeanName=null;
factoryMethodName=null; initMethodName=null; destroyMethodName=null;
defined in URL
[jar:file:/C:/My%20Data/workspace/services2/microservices/Shared-Module/build/libs/Shared-Module-1.0-SNAPSHOT.jar!/com/marketshare/SharedMain.class]]
at org.springframework.util.Assert.state(Assert.java:70)
at org.springframework.boot.test.context.SpringBootConfigurationFinder.scanPackage(SpringBootConfigurationFinder.java:69)
at org.springframework.boot.test.context.SpringBootConfigurationFinder.findFromPackage(SpringBootConfigurationFinder.java:59)
at org.springframework.boot.test.context.SpringBootConfigurationFinder.findFromClass(SpringBootConfigurationFinder.java:52)
Here is the code snippet
#RunWith(SpringRunner.class)
#WebMvcTest(CustomReportController.class)
public class CustomReportControllerTest {
}
I just want to unit test my controller. BTW I am new to spring world.
The #RunWith(SpringRunner.class) will load the spring context. To test just the controller you can use
#RunWith(MockitoJUnitRunner.class)
public class CustomReportControllerTest {
}
There is a simple approach, you can creatae a new Spring Boot Application, let's say TestApplication under your test source folder, just like
src\test\java\com\example\TestApplication.java
#SpringBootApplication
#EnableAutoConfiguration
#ComponentScan("......").
#EnableAsync
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
and add your package into the #ComponentScan, you can get all the spring boot capacities and only applicable to the test propose.
Add #SpringBootTest
#RunWith(SpringRunner.class)
#AutoConfigureMockMvc
Use these annotations on the test class and Autowire MockMvc and then you can use mockMvc.perform to test Controller methods

Spring - custom userDetailsService

I am having issues in using Spring boot with Spring Activiti. we have userDetailsService defined and its working fine with out adding activiti dependency. But with activiti my userDetailsService is getting overridden with root userDetailsService
Overriding bean definition for bean '**userDetailsService**' with a different definition: replacing [Generic bean: class [com.partshub.security.UserDetailsService]; .....l; defined in file [C:\GFApps\spring-workspace\Spring-SPA\target\classes\com\partshub\security\UserDetailsService.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.activiti.spring.boot.SecurityAutoConfiguration$UserDetailsServiceConfiguration; factoryMethodName=userDetailsService; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/activiti/spring/boot/SecurityAutoConfiguration$UserDetailsServiceConfiguration.class]]
Maven dependency added
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>5.21.0</version>
</dependency>
Appreciate your help
adding below property entry fixed my issue
spring.autoconfigure.exclude = "org.activiti.spring.boot.RestApiAutoConfiguration, org.activiti.spring.boot.SecurityAutoConfiguration, org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration"

Overriding the InfoEndpoint in Spring Cloud

Originally posted this as an issue in GitHub but might be better suited for this forum...
We are assigning some custom metadata values to our Spring Cloud services that are being registered in Eureka and we now need to have visibility to those values in the Eureka dashboard. I am trying to extend/override the /info endpoint so that our metadata is visible from the Eureka Dashboard which already provides hyperlinks to each registered service's /info endpoint. I had read that I could override the Boot autoconfigured InfoEndpoint by just adding my own version of that bean to the context. I am trying to test with the following configuration bean:
#Configuration
public class EndpointConfig {
#Bean
public InfoEndpoint infoEndpoint() throws Exception {
LinkedHashMap<String, Object> info = new LinkedHashMap<String, Object>();
info.put("name", "value");
return new InfoEndpoint(info);
}
}
When I run my service though and hit its /info endpoint I do not see this test value. I also see this in the log:
2015-04-17 14:54:23,910 main INFO DefaultListableBeanFactory - - - -
Overriding bean definition for bean 'infoEndpoint': replacing [Root
bean: class [null]; scope=; abstract=false; lazyInit=false;
autowireMode=3; dependencyCheck=0; autowireCandidate=true;
primary=false; factoryBeanName=endpointConfig;
factoryMethodName=infoEndpoint; initMethodName=null;
destroyMethodName=(inferred); defined in class path resource
[com/acme/ecom/items/config/EndpointConfig.class]] with [Root bean:
class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3;
dependencyCheck=0; autowireCandidate=true; primary=false;
factoryBeanName=org.springframework.cloud.autoconfigure.RefreshAutoConfiguration$InfoEndpointRebinderConfiguration;
factoryMethodName=infoEndpoint; initMethodName=null;
destroyMethodName=(inferred); defined in class path resource
[org/springframework/cloud/autoconfigure/RefreshAutoConfiguration$InfoEndpointRebinderConfiguration.class]]
It appears that my version of the infoEndpoint bean is being replaced with another bean coming from Spring cloud (in org/springframework/cloud/autoconfigure/RefreshAutoConfiguration$InfoEndpointRebinderConfiguration.class).
Am I reading this correctly? And if so how do I prevent it?
Thanks,
Bill
If you put your metadata in info.* e.g. info.myfoo=${eureka.instance.metadataMap.myfoo:none} it will show up in the default /info endpoint.
Don't know if this will actually help but I have this in my application.yml which I can see when I do /info on the service.
info:
component: Service Name
so when i hit the service with /info this is what i see:-
{
"component": "Service Name"
}
Hope this helps.

Resources