Search code examples
spring-bootunit-testingkotlinintegration-testingjunit5

MvcTest with mocks is integration test or unit test


If we have mocks in the MvcMock test on rest endpoint, can we call it as integration test? Definitely, I can say TestRestTemplate test is integration test as there is no mocking when I test the endpoint.

MvcMock test

@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
internal class CreateProductRestControllerMvcTest {

    @Autowired
    private lateinit var mockMvc: MockMvc

    @Autowired
    private lateinit var objectMapper: ObjectMapper

    @MockkBean
    private lateinit var createProductService: CreateProductService

    @ParameterizedTest
    @ArgumentsSource(ValidCreateProductRequests::class)
    internal fun `POST a new Product, GIVEN without any exception, THEN return Product id and status 201`(request: CreateProductRequest) {
        // Given
        every { createProductService.invoke(request.toCommand()) } returns ProductId(1L)

        // When, Then
        this.mockMvc.post(REST_PRODUCTS) {
            contentType = APPLICATION_JSON
            content = objectMapper.writeValueAsString(request)
        }
            .andExpect {
                status { isCreated() }
                content { json((objectMapper.writeValueAsString(1L))) }
            }
    }
}

TestRestTemplate Test

@SpringBootTest(webEnvironment = RANDOM_PORT, classes = [Application::class])
@ActiveProfiles("test")
@Testcontainers
@FlywayTest
@ExtendWith(FlywayTestExtension::class)
class CreateProductRestControllerIntegrationTest {

    @Autowired
    private lateinit var restTemplate: TestRestTemplate

    private lateinit var headers: HttpHeaders

    @BeforeEach
    internal fun setUp() {
        headers = HttpHeaders()
        headers.contentType = MediaType.APPLICATION_JSON
    }


    @FlywayTest
    @ParameterizedTest
    @ArgumentsSource(ValidJsonRequestBodies::class)
    internal fun `POST new Product, GIVEN valid request, THEN returns 201`(json: String) {
        // Given
        val request: HttpEntity<String> = HttpEntity(json, headers)

        // When
        val result = restTemplate.postForEntity(REST_PRODUCTS, request, String::class.java);

        // Then
        assertNotNull(result.body)
        assertEquals(HttpStatus.CREATED, result.statusCode)
    }
}

Solution

  • In my opinion, calling it an "integration test" is not completely fair. By mocking the Service you are basically testing your Controller and testing the capability of serializing and deserializing JSON, which is a completely valid test.

    In Spring world you might find these being called "slice tests" on which the point of the test is to check a given layer of your application instead of a fully-fledged integration test. More information about them in: