Can't Autowire JpaRepository in Junit test - Spring boot application
autowired, java, junit, repository, spring
Solution
Your error is actually the expected behavior of `@WebMvcTest`. You basically have 2 options to perform tests on your controller.
1. @WebMvcTest - need to use @MockBean
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));
}
}
2. @SpringBootTest - you can @Autowire beans
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);
}
}
Problem
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