Exclude EurekaClient Bean from Application Context in SpringBootApplicationTest - java

I'm trying to write a integration test against my Spring Data API with the following test configuration.
eureka:
client:
enabled: false
[..] # No other configuration part that affects discovery/eureka client
This is my test class
#SpringBootTest
#AutoConfigureMockMvc(addFilters = false)
#Transactional
class FooAPITest {
#Test
void contextLoads() {
}
}
However I have a component which injects the EurekaClient to get a service instance from it
#Component
public class ServiceClient {
#Autowired
public ServiceClient(#Qualifier("eurekaClient") EurekaClient eurekaClient) {
URI serviceUri = URI.create(eurekaClient.getNextServerFromEureka("service", false).getHomePageUrl());
}
}
So as of this service my application is not able to load the ApplicationContext.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.netflix.discovery.EurekaClient' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Qualifier(value="eurekaClient")}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:885)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789)
... 81 more
What I've tried so far
I thought about setting up a custom ContextConfiguration to exclude the ServiceClient as it is not needed in the test class. However I need to include a Configuration File which autowires the EntityManager but when I use #SpringBootApplication(classes = {Configuration.class}) the EntityManager can not be injected. This Configuration looks like that:
#Configuration
class Configuration {
#Autowired
EntityManager entityManager;
}
This produces the same error but with EntityManager Bean:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
... 81 more
Current Workaround
Currently I'm avoiding the problem by mocking the ServiceClient but I want to get rid of that code smell.
#MockBean
ServiceClient serviceClient;
#BeforeEach
void setUp() {
MockitoAnnotations.initMocks(FooAPITest.class);
}
Another workaround would be to mark the Injected Beans as not required but I don't find that practicable only to make the tests work.
What is a proper way to solve this problem?

You can try mocking the EurekaClient in your test:
#SpringBootTest
#AutoConfigureMockMvc(addFilters = false)
#Transactional
class FooAPITest {
#MockBean
private EurekaClient eurekaClient;
#Test
void contextLoads() {
}
}
This will create the EurekaClient as a mocked bean in the ApplicationContext to be injected into your service.
If you have other tests that initialize the Spring ApplicationContext, you can create a separate configuration class within the application package to be scanned (using #ConditionalOnMissingBean annotation to cover all bases):
#Configuration
public class MockEurekaConfiguration {
#Bean
#ConditionalOnMissingBean
public EurekaClient eurekaClient() {
return Mockito.mock(EurekaClient.class);
}
}

Related

#Component not being read in Spring test

I created an Integration test to test the new feature I just added but the Spring wiring is not working. The unit tests all work and the existing Spring integration tests still work but I am unable to Autowire my new class
Here is the error message –
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.xxx.xxx.etc.MyNewClassTest’: Unsatisfied dependency expressed through field 'sut'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.xxx.xxx.etc.MyNewClass ' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
The new class –
#Slf4j
#Component
public class MyNewClass extends AbstractRetryJob<Event> {
My test -
#ExtendWith(SpringExtension.class)
class MyNewClassTest {
#Autowired private MyNewClass sut;
Any idea on what is going wrong?
Adding #ExtendWith(SpringExtension.class) is not enough to create the Spring context. You need to add #SpringBootTest to your MyNewClassTest. Per the appropriate comment, you can drop #ExtendWith(SpringExtension.class)
#SpringBootTest
class MyNewClassTest {
#Autowired private MyNewClass sut;
}

How to load ServerHttpSecurity in #SpringBootTest?

I want to create a #SpringBootTest that makes use of my full configuration structure.
Problem: I'm creating an #Bean SecurityWebFilterChain that requires a ServerHttpSecurity, which is somehow missing in a test:
#SpringBootApplication
public class MainApp { ... }
//for simple testing I started with anonymous auth
#Configuration
public class ReactiveSecurityConfiguration {
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http.anonymous()
.and().csrf().disable()
.build();
}
}
#SpringBootTest
public class TestClass {
#Test
public void test() {
}
}
Result:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'securityWebFilterChain' defined in class path resource [ReactiveSecurityConfiguration.class]:
Unsatisfied dependency expressed through method 'securityWebFilterChain' parameter 0;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'org.springframework.security.config.web.server.ServerHttpSecurity' available:
expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Update
I discovered if I add the following annotations to my Test Class, the testmethod works without errors. But is that intentional?
#EnableWebFlux
#EnableWebFluxSecurity
#SpringBootTest
public class TestClass { }
I'm not certain how your project is arranged, but no, it's not intentional. You can take a look at Spring Security's Reactive Sample that demonstrates this.
It may be that your TestClass is not finding the #SpringBootConfiguration annotation attached to MainApp.
I have a spring-boot-starter-web dependency pulled somewhere in the classpath. Removing it resolved the problem.
If both web and webflux dependency should be kept, it's still possible to run a test in reactive only, with:
#SpringBootTest(properties = "spring.main.web-application-type=REACTIVE")
class MyWebFluxTests {
// ...
}

#Profile in #Configuration --> Failed to load ApplicationContext

I have 2 configurations in one Spring Batch application, each of them is annotated with #Profile
#Configuration
#Profile("jobA")
public class JobA {
...
...
#Bean
public Job job(Step stepForA) {
...
}
}
#Configuration
#Profile("jobB")
public class JobB {
...
...
#Bean
public Job job(Step stepForB) {
...
}
}
I have a test to run JobB
#RunWith(SpringRunner.class)
#SpringBootTest(classes = { TestJobB.Context.class, JobB.class, JdbcTemplateAutoConfiguration.class, DataSourceAutoConfiguration.class })
#ActiveProfiles("testB")
#TestExecutionListeners(listeners = { DependencyInjectionTestExecutionListener.class })
public class TestJobB extends AbstractTestJob {
...
}
Running the test gives me the error:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'jobLauncherTestUtils': Unsatisfied dependency expressed through method 'setJob' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.batch.core.Job' available: expected at least 1 bean which qualifies as autowire candidate.
The weird thing is, if I dont use #Profile in the 2 Configurations, everything is fine. Any annotation I am missing here?
Thanks, Hadi
Double check your profile names. According to your example, the two configurations are annotated with #Profile("jobA") and #Profile("jobB") respectively. However in your test, you have defined the profile as #ActiveProfiles("testB").
As you noticed, removal of the #Profile annotation in the two configurations they will always be enabled if they are imported correctly. Consequently, the test will use JobB since it declared in the #SpringBootTest annotation.

SpringBoot and JUnit - Testing Service class - Failed to load Application Context

I'm trying to run a unit test on a service class in a Spring Boot Application
i would like to try this test
#RunWith(SpringRunner.class)
#SpringBootTest(classes=Application.class) //my #SpringBootApplication class
public class UserServiceTest { //i'm testing my UserService implementation
#TestConfiguration
static class UserServiceContextConfiguration {
#Bean
public IUserService service() {
return new UserService();
}
}
#Autowired
private IUserService service;
#MockBean
private UserRepository repository;
#Before
public void setUp() {
User me = new User();
me.setEmail("admin#admin.com");
Mockito.when(repository.findByEmail(me.getEmail())).thenReturn(me);
}
#Test
public void whenValidEmail_thenFindUser() {
String email = "admin#admin.com";
User found = service.findByEmail(email);
assertThat(found.getEmail()).isEqualTo(email);
}
}
But when launching the test i get this exception
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.myapp.service.UserServiceTest': Unsatisfied dependency expressed through field 'service'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.myapp.service.interfaces.IUserService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Maybe it is not clear to me but #TestConfiguration should allow me to define my beans from the application to use them in the tests and #SpringBootTest should load all the application context from the app for the test environment...
By providing classes=Application.class you turned off automatic scanning of inner configuration classes.
Either remove the explicit classes parameter - SpringRunner will search for SpringBootApplication annotated class in current packages and parent packages and also search for inner configuration classes,
or add this to your #SpringBootTest
#SpringBootTest(classes= {Application.class, UserServiceContextConfiguration.class })

Spring Boot 1.4 - TestRestTemplate Unsatisfied dependency exception

Have a very light Spring Boot 1.4 project, generated from start.spring.io.
Trying to run an intergration test for #RestController with #RequestBody using TestRestTemplate, but there's no success because of a startup exception.
The only configuration class:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Configuration file application.properties has almost nothing except of security.ignored=/** for the test purposes.
The test class:
#RunWith(SpringRunner.class)
#SpringBootTest
#DataJpaTest
public class MyControllerTest {
private Logger log = Logger.getLogger(getClass());
#Autowired
private TestRestTemplate restTemplate;
#Autowired
private TestEntityManager entityManager;
#Before
public void init() {
log.info("Initializing...");
}
#Test
public void addTest() throws Exception {
log.info("MyController add test starting...");
// restTemplate usage
log.info("MyController add test passed");
}
}
... but during the test startup I get the following exception:
ERROR 6504 --- [ main] o.s.test.context.TestContextManager : Caught exception while allowing TestExecutionListener [org.springframework.boot.test.autoconfigure.AutoConfigureReportTestExecutionListener#5444f1c3] to prepare test instance [com.myproject.controllers.MyControllerTest#5d2bc446]
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.myproject.controllers.MyControllerTest': Unsatisfied dependency expressed through field 'restTemplate': No qualifying bean of type [org.springframework.boot.test.web.client.TestRestTemplate] found for dependency [org.springframework.boot.test.web.client.TestRestTemplate]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.boot.test.web.client.TestRestTemplate] found for dependency [org.springframework.boot.test.web.client.TestRestTemplate]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:569) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
According to the doc it's not required to configure TestRestTemplate anywhere. However, I've added the latest Apache Http Client to the classpath as it recommended.
What have I missed?
You are specifying #DataJpaTest which tells Spring to exclude any wiring of the web context for the tests. As such there is no TestRestTemplate created. Read this blog for more details around testing slices of your application: https://spring.io/blog/2016/04/15/testing-improvements-in-spring-boot-1-4#testing-application-slices
I had a similar problem running the main class on Eclipse using Serenity BDD tests with a spring-boot. It starts to fail after I have added the spring-boot-test-autoconfigure test dependency. That happens because Eclipse put everything in just one classloader. In order to fix this error, I have created one configuration class overriding the default behavior of the spring-boot. This code was based in one spring class (the scope not is public) SpringBootTestContextCustomizer.TestRestTemplateFactory
#TestConfiguration
public class TestConfig {
// Overriding Default Spring Boot TestRestTemplate to allow
// execute the main method from Eclipse (mixed Classloader)
#Bean
#Primary
public TestRestTemplate testRestTemplate(ApplicationContext context, RestTemplateBuilder templateBuilder) {
final AbstractConfigurableEmbeddedServletContainer container = context.getBean(AbstractConfigurableEmbeddedServletContainer.class);
final boolean sslEnabled = container.getSsl() != null && container.getSsl().isEnabled();
final TestRestTemplate template = new TestRestTemplate(templateBuilder.build(), null, null, sslEnabled? new HttpClientOption[]{}: new HttpClientOption[]{HttpClientOption.SSL});
template.setUriTemplateHandler(new LocalHostUriTemplateHandler(context.getEnvironment(), sslEnabled ? "https" : "http"));
return template;
}
}

Categories