I have 3 separate projects, bound by pom.xml
main myapp folder with pom.xml having modules section:
<modules>
<module>myapp-dao</module>
<module>myapp-webapp</module>
<module>myapp-configuration</module>
</modules>
3 projects inside myapp folder (each having its own pom.xml)
myapp-dao
myapp-configuration
myapp-webapp
I am writing a JUnit test for a #RestController class in the myapp-webapp module (don't worry about the #Test contents, it is just a skeleton, it will be expanded when I will be able to run the test):
#RunWith(SpringRunner.class)
#AutoConfigureMockMvc
#WebMvcTest(ContentController.class)
public class ContentControllerTest {
#Autowired
private MockMvc mvc;
#MockBean
private ContentService contentService;
#MockBean
private HyperlinkReferenceService hyperlinkReferenceService;
#Test
public void givenEmployees_whenGetEmployees_thenReturnJsonArray() throws Exception {
given(contentService.findContentUsedAsTemplateIn(1, 0)).willReturn(null);
mvc.perform(get("/portal/content/1/references/usedAsTemplateIn").contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andExpect(jsonPath("$", hasSize(1)));
}
}
When I am trying to run the test, I get:
java.lang.IllegalStateException: Failed to load ApplicationContext
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.pro4people.msg.ServletInitializer]; nested exception is java.io.FileNotFoundException: class path resource [myapp.properties] cannot be opened because it does not exist
I have resolved this problem by copying myapp-configuration/target/myapp.properties to myapp-webapp/src/main/test/resources/myapp.properties
This solved the above problem, but another problem came out:
java.lang.IllegalStateException: Failed to load ApplicationContext
Description:
Field userRepository in com.company.myapp.service.UserServiceImpl required a bean of type 'com.company.myapp.repository.UserRepository' that could not be found.
Action:
Consider defining a bean of type 'com.company.myapp.repository.UserRepository' in your configuration.
But really, I am not even using the UserRepository in this test, so I presume that there is a Spring context problem somewhere around. The application is normally built to a war and deployed to Tomcat, and only in its wared state everything is correctly injected and bound.
How can I omit this problem? Whatever I am trying to do, the test is raising the spring context, and when I remove #WebMvcTest(ContentController.class), I get:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.company.myapp.controller.portal.json.ContentControllerTest': Unsatisfied dependency expressed through field 'mvc'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.test.web.servlet.MockMvc' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Which seems to be obvious.
Use Context configuration on top of your controller test class.
#ContextConfiguration(classes = {ContentController.class})
Below code works for unit test for controller.
#RunWith(MockitoJUnitRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = {ContentController.class})
public class ContentController {
private MockMvc mockMvc;
#InjectMocks
private ContentController contentController;
#Mock
private ContentService contentService;
....
/**
* Configure the mockMvc with Controller.
*/
#Before
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(contentController).build();
}
#Test
your test here() {
//use Mockito.when(statement).thenReturn(value);
//rest remain same using mockMVC
mockMvc.perform(...)
}
Related
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;
}
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 {
// ...
}
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 })
I am attempting the following unit test of a DAO.
I am unable to get the DataSource recognized.
Can I get a tip on how to resolve this?
Details below
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class EntityDaoTest {
#Autowired
protected EntityDao entityDao;
#Before
public void setup()
{
}
#Test
public void test() throws InternalServerException
{
List<Entity> entities = entityDao.list();
assert(entities.size()==0);
}
}
The relevant aspects of the DAO class are as follows
#Repository
public class EntityDao extends GenericDao<Entity>{
public EntityDao(DataSource dataSource) {/.../}
}
My src/test/resources/application.properties file is as follows
# Database
spring.datasource.url=jdbc:mysql://localhost:3306/db
spring.datasource.username=dbuser
spring.datasource.password=dbpass
Trace from running as JUnit test in Eclipse
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'entityController': Unsatisfied dependency expressed through field 'entityDao': Error creating bean with name 'entityDao' defined in file .../target/classes/hitstpa/dao/EntityDao.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type [javax.sql.DataSource] found for dependency [javax.sql.DataSource]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {};
...
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'entityDao' defined in file [/home/fmason/workspace/hitstpa/target/classes/hitstpa/dao/EntityDao.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type [javax.sql.DataSource] found for dependency [javax.sql.DataSource]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] found for dependency [javax.sql.DataSource]: expected at least 1 bean which qualifies as autowire candidate for this dependency. ...`
Application structure
-src
--main
---java
----Application.java
----com
----hitstpa
-----controller
-----dao
------EntityDao.java
-----model
---resources
----application.properties
--test
---java
----hitstpa
-----dao
------EntityDaoTestDOTjava
---resources
----applicationDOTproperties
First of all for integration tests you need an integration Db with some fixed data.
Now you need to create a configuration class which will create the
integration test specific dependencies(I have named it as DbConfig
.java)
Next is add #ContextConfiguration annotation to the integration test
class and provide DbConfig.java, so that when test runs it will
create the datasource dependency and inject it to the container
Sample Code
#Configuration
public class DbConfig {
#Bean
public DataSource dataSource() {
//Create the DataSource with integration-DB properties
return dataSource;
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
#ContextConfiguration(classes=DbConfig.class)
public class EntityDaoTest {
}
For the record, I believe this is not a good unit test. This test requires that a mysql databases exists on localhost.
Anyhow, the errors suggest that the Spring Context isn't loaded correctly. When using SpringBootTest, Spring looks for the configuration using the test's package as root. So, if it's lower than your Configuration classes, it won't them.
Take a look at Spring's documentation:
The search algorithm works up from the package that contains the test
until it finds a #SpringBootApplication or #SpringBootConfiguration
annotated class. As long as you’ve structure your code in a sensible
way your main configuration is usually found.
Solution:
You can either move your tests to the same level as your SpringBoot Main class or change it to: #SpringBootTest(classes = YourSpringBootMainClass.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;
}
}