Load 1 bean from #configuration in SpringBoot - spring

PIDClient has HttpClient (Java 11) as a dependency in its constructor. I want to autowire this so I created an #Configuration annotated class named SpringConfiguration. I got it working with the code below.
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {PIDClient.class, SpringConfiguration.class})
public class PIDClientTest {
My issue with this is, now it loads all the beans in SpringConfiguration while I only need HttpClient bean. I tried the code below but that gave me a No qualifying bean of type 'java.net.http.HttpClient'.
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {PIDClient.class, HttpClient.class})
public class PIDClientTest {
Here's a screenshot of the projects' directory structure in case it's needed with the relevant classes open.
Is there a better way?

Related

Autowiring configuration class spring

I'm wondering whether it's possible to autowire a class annotated with #Configuration into any annotated class (#Component, #SpringBootTest, etc)? I know it's possible between #Configuration classes, but I can't find a straight answer on if it's possible outside #Configuration classes (both test and non-test classes). Sample code to illustrate what I mean below:
#Configuration
public class Config {
//Anything in here
}
//any non-Configuration annotation
public class Autowired {
#Autowire
Config config; //like this
}
If you are looking at the source code of #Configuration annotation you can see it's annotated itself with #Component, making annotated classes with it also Spring components, so making them available for injection.
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Component
public #interface Configuration {
Yes. you can autowire configuration class as #configuration annotation contains #component

Exclude elasticsearchTemplate from Spring-Boot Test

I have an application that use Elasticsearch and I'd like to disable this integration when I'm testing some controllers. How can I disable elasticsearchTemplate on Spring-Boot test?
Application.class:
#SpringBootApplication
#EnableElasticsearchRepositories(basePackages = "com.closeupinternational.comclosure.elasticsearch")
public class Application {
...
Repository.class:
#Repository
public interface PipelineRepository extends ElasticsearchRepository<Pipeline, String> {
...
Test Controller.class:
#ExtendWith(SpringExtension.class)
#EnableAutoConfiguration(exclude = {ElasticsearchDataAutoConfiguration.class,
ElasticsearchRepositoriesAutoConfiguration.class})
#WebMvcTest(ProductionCycleExecutionController.class)
#Slf4j
public class ProductionCycleExecutionControllerTest {
#Autowired
private MockMvc mvc;
#MockBean
private ProductionCycleExecutionService prodCycleExecService;
...
I'm not using inside ProductionCycleExecutionService and I don't wanna try to test elasticsearch repository PipelineRepository at this moment.
Error:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pipelineRepository' defined in
com.closeupinternational.comclosure.elasticsearch.PipelineRepository defined in
#EnableElasticsearchRepositories declared on Application: Cannot resolve reference to bean
'elasticsearchTemplate' while setting bean property 'elasticsearchOperations'; nested exception is org.springframework.beans.factory
Just remove #ExtendWith(SpringExtension.class) and #EnableAutoConfiguration(exclude = {ElasticsearchDataAutoConfiguration.class, ElasticsearchRepositoriesAutoConfiguration.class})
These annotations aim to bootstrap the whole Spring context and configure it
#WebMvcTest should be enough in your case as it bootstraps web-related context only
Upd
If you have any dependencies in your ProductionCycleExecutionController (like elasticsearchTemplate you mentioned) then mock them like this if you don't need to define their behavior, as follows:
#MockBeans(value = {#MockBean(YourBean1.class), #MockBean(YourBean2.class), #MockBean(YourBean3.class)})
If you do need to define mocking behavior then mock as property in class:
#MockBean
private YourBean yourBean;

IntelliJ Idea + Could not autowire. No beans of type found

I keep seeing below error in my IntelliJ Idea, however the code works fine during execution.
Could not autowire. No beans of 'PortfolioRequestHandler' type found. less... (Ctrl+F1)
Inspection info:Checks autowiring problems in a bean class.
Sample Code
#ActiveProfiles("test")
#RunWith(SpringRunner.class)
#DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
#SpringBootTest(classes = {Application.class})
public class PortfolioRequestHandlerTest {
#Autowired
private PortfolioRequestHandler portfolioRequestHandler;
...
...
}
How do I get rid of this? I am using IntelliJ Idea ULTIMATE 2018.2
Are you sure that your Spring beans are wired correctly and that it's an IDE problem?
check if your PortfolioRequestHandler class is annotated with #Service, #Component or #Repository (bean config via component scanning)
otherwise check if your bean is wired in a #Configuration annotated class -> in that case there should be a method that returns an instance of type PortfolioRequestHandler and that's annotated with #Bean
try adding a configuration class (as mentioned in 2.) and add this class to your #SpringBootTest(classes = {...} annotation; see example below
#Configuration
public class CustomBeanConfig {
#Bean
public PortfolioRequestHandler get PortfolioRequestHandler() {
return new PortfolioRequestHandler();
}
}
#SpringBootTest(classes = {Application.class, CustomBeanConfig.class})
have a look at this one, maybe helps: https://stackoverflow.com/a/50267869/150623

How to exclude classes with #Configuration in #SpringBootApplication testing

I am using a dependent module called spring-cloud-aws. It has a #Configuration class as org.springframework.cloud.aws.messaging.config.annotation.SqsConfiguration
In my SpringBoot JUnit test case the SqsConfiguration class is getting detected and Beans are getting initialized. I want to exclude this Configuration in class in my JUNit test case. How to achieve this ?
I tried using #ComponentScan it didn't work.
#RunWith(SpringRunner.class)
#SpringBootTest(classes = SQLTestConfig.class)
#ActiveProfiles("test")
public class BusinessManagerTest {
}
#TestConfiguration
#ComponentScan(basePackages = {"package1","package1"},
excludeFilters = {#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = SqsConfiguration.class)})
#Profile("test")
class SQLTestConfig {
#Bean
public SomeBean beans() {
return new SomeBean();
}
}
Loading this configuration class requires aws credentials to be available. I don't want to inject credentials for running a simple Bean test case.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'simpleMessageListenerContainer' defined in class path resource [org/springframework/cloud/aws/messaging/config/annotation/SqsConfiguration.class]: Invocation of init method failed; nested exception is com.amazonaws.services.sqs.model.AmazonSQSException: The security token included in the request is expired
There are multiple ways to exclude specific auto-configuration during testing:
exclude via properties in your application-test.properties
spring.autoconfigure.exclude=org.springframework.cloud.aws.messaging.config.annotation.SqsConfiguration
exclude via #TestPropertySource:
#RunWith(SpringRunner.class)
#ActiveProfiles("test")
#SpringBootTest(classes = SQLTestConfig.class)
#TestPropertySource(properties ="spring.autoconfigure.exclude=org.springframework.cloud.aws.messaging.config.annotation.SqsConfiguration")
exclude via #EnableAutoConfiguration, e.g.:
#RunWith(SpringRunner.class)
#ActiveProfiles("test")
#SpringBootTest(classes = SQLTestConfig.class)
#EnableAutoConfiguration(exclude=SqsConfiguration.class)
Choose one that suites you better ;)
So to disable the auto-loading of all Beans for a Test, the test class can explicitly mention the dependencies required. This can be done using ContextConfiguration annotation. eg,
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {EmployeeService.class})
public class EmployeeLeavesTest {
#Autowired
private EmployeeService employeeService;
}
In this eg, only EmployeeService class will be available and other beans will not be loaded.

How to load mongo repository to spring test application context?

I have to implement some test for some spring application. I am using #SpringBootTest annotation in my test:
#SpringBootTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MyTest(){
//some tests...
}
It works fine, but i do not want to load all application context and and limit it by adding one or more nessecary configuration class. I done it with #ContextHierarchy:
#SpringBootTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#ContextHierarchy(ContextConfiguration(classes = [SomeCofigClass1::class, SomeConfigClass2::class]))
class MyTest(){
//some tests...
}
//for example
class SomeCofigClass1(){
#Bean
fun(someMongoRepository: SomeMongoRepository){ \\<-- Problem is here
return SomeService(someMongoRepository)
}
}
/**
* My repository.
*/
interface SomeMongoRepository : MongoRepository<Job, String> {}
Because of context is partially loaded i got a error:
No qualifying bean of type 'SomeMongoRepository' available:....
How can i load repository in test application context?
I already tried:
1) Added #AutoConfigureDataMongo. I got error java.lang.IllegalStateException: Unable to retrieve #EnableAutoConfiguration base packages
#SpringBootTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#ContextHierarchy(ContextConfiguration(classes = [SomeCofigClass1::class, SomeConfigClass2::class]))
#AutoConfigureDataMongo
2) Replaced #SpringBootTest by #DataMongoTest. I got error Unable to retrieve #EnableAutoConfiguration base packages
#DataMongoTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#ContextHierarchy(ContextConfiguration(classes = [SomeCofigClass1::class, SomeConfigClass2::class]))
3) With #DataMongoTest replaced #ContextHierarchy by #Import. With #Import annotation it loads all application context. This is not suit for me.
#DataMongoTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#Import(SomeCofigClass1::class, SomeConfigClass2::class)
Add #RunWith(SpringRunner.class) to load Spring's ApplicationContext during the test.
Furthermore, classes can be selected by using the #SpringBootTest#classes attribute (or #ContextConfiguration):
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {SomeCofigClass1.class, SomeConfigClass2.class})
If your test makes use of inner Configuration classes, be sure to make them static (and add #Configuration). From the documentation:
If you omit the classes attribute from the #ContextConfiguration annotation, the TestContext framework tries to detect the presence of
default configuration classes. Specifically,
AnnotationConfigContextLoader and AnnotationConfigWebContextLoader
detect all static nested classes of the test class that meet the
requirements for configuration class implementations, as specified in
the #Configuration javadoc.

Resources