Hi All
I’m trying to execute a Junit test in a Spring boot application, the Junit should test some CRUD operations, I’m using Spring Repositories specifically JpaRepository.
The Repository calss:
package au.com.bla.bla.bla.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import au.com.bla.bla.bla.entity.Todo;
public interface TodoRepository extends JpaRepository<Todo, Integer> {
}
TodoController class
package au.com.bla.bla.bla.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import au.com.bla.bla.bla.entity.Todo;
import au.com.bla.bla.bla.repository.TodoRepository;
import java.util.List;
import java.util.Map;
@RestController
@CrossOrigin
public class TodoController
{
static final String TEXT = "text";
@Autowired
private TodoRepository todoRepository;
...
@RequestMapping(path = "/todo", method = RequestMethod.POST)
public Todo create(@RequestBody Map<String, Object> body)
{
Todo todo = new Todo();
todo.setCompleted(Boolean.FALSE);
todo.setText(body.get(TEXT).toString());
todoRepository.save(todo);
return todo;
}
...
The JUnit:
package au.com.bla.bla.bla.controller;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import au.com.bla.bla.bla.repository.TodoRepository;
@WebMvcTest(TodoController.class)
@RunWith(SpringRunner.class)
public class TodoControllerTest {
@Autowired
private MockMvc mvc;
@Autowired
private TodoController subject;
@Before
public void setUp() {
}
@Test
public void testCreate() throws Exception {
String json = "{\"text\":\"a new todo\"}";
mvc.perform(post("/todo").content(json)
.contentType(APPLICATION_JSON)
.accept(APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(3))
.andExpect(jsonPath("$.text").value("a new todo"))
.andExpect(jsonPath("$.completed").value(false));
assertThat(subject.getTodos()).hasSize(4);
}
...
Problem:
When executing the Junit I end up with this exception:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'todoController': Unsatisfied dependency expressed through field 'todoRepository': No qualifying bean of type [au.com.bla.bla.bla.repository.TodoRepository] found for dependency [au.com.bla.bla.bla.repository.TodoRepository]: 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 [au.com.bla.bla.bla.repository.TodoRepository] found for dependency [au.com.bla.bla.bla.repository.TodoRepository]: 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]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:349) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
…
Can anyone help with this ? Thanks in advance
To activate the Spring JPA repository support, we can use the @EnableJpaRepositories annotation and specify the package that contains the DAO interfaces: @EnableJpaRepositories(basePackages = "com.
Also note that we can wire other spring beans in our jUnit test classes using @Autowired annotation.
Crud Repository doesn't provide methods for implementing pagination and sorting. JpaRepository ties your repositories to the JPA persistence technology so it should be avoided. We should use CrudRepository or PagingAndSortingRepository depending on whether you need sorting and paging or not.
Your error is actually the expected behavior of @WebMvcTest
.
You basically have 2 options to perform tests on your controller.
With @WebMvcTest
, a minimal spring context is loaded, just enough to test the web controllers. This means that your Repository isn't available for injection:
Spring documentation:
@WebMvcTest
will auto-configure the Spring MVC infrastructure and limit scanned beans to @Controller, @ControllerAdvice, @JsonComponent, Filter, WebMvcConfigurer and HandlerMethodArgumentResolver.
Assuming the goal is just to test the Controller, you should inject your repository as a mock using @MockBean
.
You could have something like:
@RunWith(SpringRunner.class)
@WebMvcTest(TodoController.class)
public class TodoControllerTest {
@Autowired
private MockMvc mvc;
@Autowired
private TodoController subject;
@MockBean
private TodoRepository todoRepository;
@Test
public void testCreate() throws Exception {
String json = "{\"text\":\"a new todo\"}";
mvc.perform(post("/todo").content(json)
.contentType(APPLICATION_JSON)
.accept(APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(3))
.andExpect(jsonPath("$.text").value("a new todo"))
.andExpect(jsonPath("$.completed").value(false));
Mockito.verify(todoRepository, Mockito.times(1)).save(any(Todo.class));
}
}
If you want to load the whole application context, then use @SpringBootTest
: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html
You'd have something like this:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class TodoControllerTest {
private MockMvc mvc;
@Autowired
TodoController subject;
@Autowired
private WebApplicationContext context;
@Before
public void setup() {
this.mvc = MockMvcBuilders.webAppContextSetup(context).build();
}
@Test
public void testNoErrorSanityCheck() throws Exception {
String json = "{\"text\":\"a new todo\"}";
mvc.perform(post("/todo").content(json)
.contentType(APPLICATION_JSON)
.accept(APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(3))
.andExpect(jsonPath("$.text").value("a new todo"))
.andExpect(jsonPath("$.completed").value(false));
assertThat(subject.getTodos()).hasSize(4);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With