Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package me.nettee.board.adapter.driving.web

import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import io.kotest.core.spec.style.FreeSpec
import me.nettee.board.adapter.driving.web.dto.BoardQueryDto.BoardDetailResponse
import me.nettee.board.adapter.driving.web.mapper.BoardDtoMapper
Expand All @@ -11,20 +8,19 @@ import me.nettee.board.application.model.BoardQueryModels.BoardSummary
import me.nettee.board.application.model.BoardQueryModels.BoardDetail
import me.nettee.board.application.usecase.BoardReadByStatusesUseCase
import me.nettee.board.application.usecase.BoardReadUseCase
import me.nettee.core.config.JacksonTestConfig
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.argThat
import org.mockito.Mockito.`when`
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Import
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageImpl
import org.springframework.data.domain.Pageable
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
import org.springframework.test.context.bean.override.mockito.MockitoBean
import org.springframework.test.context.junit.jupiter.SpringExtension
import org.springframework.test.web.servlet.MockMvc
Expand All @@ -35,6 +31,7 @@ import java.time.Instant

@WebMvcTest(BoardQueryApi::class)
@ExtendWith(SpringExtension::class)
@Import(JacksonTestConfig::class)
class BoardQueryApiTest(
@MockitoBean private val boardReadUseCase: BoardReadUseCase,
@MockitoBean private val boardReadByStatusesUseCase: BoardReadByStatusesUseCase,
Expand Down Expand Up @@ -107,11 +104,6 @@ class BoardQueryApiTest(
) -> Page<BoardSummary>

beforeSpec {
val objectMapper = ObjectMapper().apply {
registerModule(JavaTimeModule())
setSerializationInclusion(JsonInclude.Include.NON_NULL)
}

boardReadSummaryModelPage = { boardList, pageable, boardStatus ->
val filteredBoards = boardList
.takeIf { it.isNotEmpty() }
Expand All @@ -137,9 +129,6 @@ class BoardQueryApiTest(
)
}

val jsonResult = objectMapper.writeValueAsString(boardDetailWithNull)
val nonNullResponse = objectMapper.readValue(jsonResult, BoardDetail::class.java)

`when`(boardReadUseCase.getBoard(1L)).thenAnswer { boardDetail }
`when`(boardReadUseCase.getBoard(2L)).thenAnswer { boardDetailWithNull }
`when`(boardReadUseCase.getBoard(argThat { it != 1L && it != 2L })).thenThrow(ResponseStatusException(HttpStatus.NOT_FOUND))
Expand All @@ -154,21 +143,6 @@ class BoardQueryApiTest(
boardReadSummaryModelPage(boardList, pageable, statuses)
}
`when`(boardDtoMapper.toDtoDetail(boardDetail)).thenReturn(BoardDetailResponse(boardDetail))
`when`(boardDtoMapper.toDtoDetail(boardDetailWithNull)).thenReturn(BoardDetailResponse(nonNullResponse))
}
}) {
@TestConfiguration
class JacksonTestConfig {
@Bean
fun objectMapper(): ObjectMapper {
return ObjectMapper()
.registerModule(JavaTimeModule())
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
}

@Bean
fun mappingJackson2HttpMessageConverter(objectMapper: ObjectMapper): MappingJackson2HttpMessageConverter {
return MappingJackson2HttpMessageConverter(objectMapper)
}
`when`(boardDtoMapper.toDtoDetail(boardDetailWithNull)).thenReturn(BoardDetailResponse(boardDetailWithNull))
}
}
})
23 changes: 23 additions & 0 deletions src/test/kotlin/me/nettee/core/config/JacksonTestConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package me.nettee.core.config

import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter

@TestConfiguration
class JacksonTestConfig {
@Bean
fun objectMapper(): ObjectMapper {
return ObjectMapper()
.registerModule(JavaTimeModule())
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
}

@Bean
fun mappingJackson2HttpMessageConverter(objectMapper: ObjectMapper): MappingJackson2HttpMessageConverter {
return MappingJackson2HttpMessageConverter(objectMapper)
}
}
Comment on lines +10 to +23
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 이 설정 파일이 명시적으로 필요한 이유가 무엇인가요?

이 설정 파일이 어떨 때 필요하고, 있을 때와 없을 때 어떤 차이가 있는지 궁금합니다.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@merge-simpson 바쁜 와중에도 질문 남겨주셔서 감사합니다.

메인 프로젝트의 Jackson 설정이 테스트 환경에 적용되지 않는 문제를 해결하기 위해,
테스트 환경에서도 동일한 설정이 유지되도록 ObjectMapper와 MappingJackson2HttpMessageConverter를 수동으로 @bean 등록하였습니다.

  • ObjectMapper 설정
    • registerModule(JavaTimeModule()) → 날짜 타입 변환을 지원하도록 설정
    • setSerializationInclusion(JsonInclude.NON_NULL) → null 값이 JSON 직렬화되지 않도록 설정
  • MappingJackson2HttpMessageConverter 등록 이유
    • HTTP 요청/응답 변환 시, 등록한 ObjectMapper가 사용되도록 설정

이 설정 파일은 컨트롤러 테스트에서 활용하는 것이 적절해 보이며, 이를 적용하면 HTTP 통신 테스트에서 null 값이 JSON 직렬화되지 않는 차이가 있습니다.