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 {
// ...
}
Related
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.
I have a SpringBoot app (REST Architecture )
I have this service defined that uses Constructor Dependency Injection
#Service
#Slf4j
public class HostelService {
private final HostelRepository hostelRepository;
HostelService(HostelRepository hostelRepository) {
this.hostelRepository = hostelRepository;
}
}
I want to use it in a integration test:
#RunWith(SpringRunner.class)
#SpringBootTest
public class HostelServiceIntegrationTest {
public static final String Hostel_1 = "Hostel::1";
#Autowired
protected HostelRepository hostelRepository;
#Autowired
private HostelService hostelService;
//...
}
#Repository
public interface HostelRepository extends CouchbaseRepository<Hostel, String> {
}
but I have this error:
..Unsatisfied dependency expressed through constructor parameter 0;
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'io.clouding.repository.HostelRepository' available: expected at
least 1 bean which qualifies as autowire candidate. Dependency
annotations: {}
and on the Application:
#SpringCloudApplication
#SpringBootApplication
#EnableJpaRepositories("io.clouding.repository")
#ComponentScan(basePackages = { "io.clouding.repository" })
public class Application implements WebMvcConfigurer {
..
}
I hope your problem is that your bean, HostelRespository is not getting created. And it's a CouchbaseRepository. I hope it's not even created in non-test environment also.
What you have to do is, instead of
#EnableJpaRepositories("io.clouding.repository")
add
#EnableCouchbaseRepositories(basePackages = {"io.clouding.repository"})
It will help run-time to create the bean for you. So your specific problem will be solved.
Note:
Please note that, if you haven't still configured the underlying configurations needed for spring-data-couchbase, you might see some other errors after fixing this, that you have to fix by configuration. You may refer this.
The error says it, you probably have a RequestRepository and the error is inside it; check the constructor/dependencies in it and see if something is not being injected or show the RequestRepository and the full error stack trace.
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 })
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;
}
}
I have a Spring boot app and just added security to it. That breaks my tests as the context won't even load.
Tests are dealing with service and persistence layers, so the security should not affect them at all. That is meant for the controllers.
I followed an official github sample and have this simple security configuration:
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").csrf().disable();
http.authorizeRequests()
.antMatchers("/user").permitAll()
.anyRequest().authenticated();
}
}
Running the app works fine and as expected. But running tests, such as:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = DeadlinesApplication.class)
public class TaskDAOHibernateTest {
#Test
#Transactional
public void someTest() {...}
}
Fails with:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'applicationSecurity': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.setAuthenticationConfiguration(org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Adding the #EnableWebSecurity annotation to the class does allow the tests to pass, however in the docs there is written:
To switch off the default web security configuration completely you can add a bean with #EnableWebSecurity
And I want to keep the default configuration, only selectively override it.