dickyj
dickyj

Reputation: 1870

Spring Annotation @WebMvcTest does not work in an app that has Jpa repositories

I have a Spring App that uses JPA repositories (CrudRepository interfaces). When I try to test my controller using the new Spring test syntax @WebMvcTest(MyController.class), it fails coz it tries to instantiate one of my service class that uses JPA Repository, does anyone has any clues on how to fix that? The app works when I run it.

Here is the error:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in com.myapp.service.UserServiceImpl required a bean of type 'com.myapp.repository.UserRepository' that could not be found.

Action:

Consider defining a bean of type 'com.myapp.repository.UserRepository' in your configuration.

Upvotes: 11

Views: 10460

Answers (4)

PhongPhamIUH
PhongPhamIUH

Reputation: 74

You should manual config Data Jpa(https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.java-config) then use @Import annotation in test file instead of use @SpringBootTest to load all bean in system that will very expense(time and resource) when run test

Upvotes: 0

jcflorezr
jcflorezr

Reputation: 336

I was able to unit test a Rest Controller by implementing junit 5 and using @SpringJUnitConfig along with @WebMvcTest. I am using Spring Boot 2.4.5 and this is my example:

@SpringJUnitConfig
@WebMvcTest(controllers = OrderController.class)
class OrderControllerTest {

    @Autowired
    private MockMvc mockMvc;

    // This is a Mock bean of a Spring Feign client that calls an external Rest Api
    @MockBean
    private LoginServiceClient loginServiceClient;

    // This is a Mock for a class which has several Spring Jpa repositories classes as dependencies
    @MockBean
    private OrderService orderService;

    @DisplayName("should create an order")
    @Test
    void createOrder() throws Exception {

        OrderEntity createdOrder = new OrderEntity("123")

        when(orderService.createOrder(any(Order.class))).thenReturn(createdOrder);

        mockMvc.perform(post("/api/v1/orders").contentType(MediaType.APPLICATION_JSON).content("{orderId:123}"))
            .andExpect(status().isCreated())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))TODO: here it will go the correlationId
            .andExpect(jsonPath("$.orderId").value("123"));
    }
}

Please only use @SpringBootTest when you are implementing integration tests.

Upvotes: 3

Edor Linus
Edor Linus

Reputation: 1146

I faced this same problem. Using @SpringBootTest and @AutoConfigureMockMvc worked perfectly for me.

Upvotes: 2

Liping Huang
Liping Huang

Reputation: 4476

According to the doc

Using this annotation will disable full auto-configuration and instead apply only configuration relevant to MVC tests (i.e. @Controller, @ControllerAdvice, @JsonComponent Filter, WebMvcConfigurer and HandlerMethodArgumentResolver beans but not @Component, @Service or @Repository beans).

This annotion only apply on the Spring MVC components.

If you are looking to load your full application configuration and use MockMVC, you should consider @SpringBootTest combined with @AutoConfigureMockMvc rather than this annotation.

Upvotes: 15

Related Questions