[#15] feat: 카페 메뉴 관련 테스트 작성

- 카페 메뉴 관련 조회 로직 mock 테스트 작성(CafeMenuService)
- CafeMenuSerivce 트랜잭션 선언 수정
- TODO 내용 추가 작성
This commit is contained in:
beaniejoy
2022-09-24 22:08:10 +09:00
parent d9401930d8
commit f798e278b8
5 changed files with 251 additions and 163 deletions

View File

@@ -9,11 +9,12 @@ import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
@Service
@Transactional(readOnly = true)
@Transactional
class CafeMenuService(
private val cafeMenuRepository: CafeMenuRepository,
private val menuOptionService: MenuOptionService
) {
@Transactional(readOnly = true)
fun getDetailedInfoByMenuId(menuId: Long, cafeId: Long): CafeMenuDetailedInfo {
val cafeMenu = cafeMenuRepository.findByIdOrNull(menuId)
?: throw CafeMenuNotFoundException(menuId = menuId, cafeId = cafeId)
@@ -21,7 +22,6 @@ class CafeMenuService(
return CafeMenuDetailedInfo.of(cafeMenu)
}
@Transactional
fun updateInfoAndBulkUpdate(menuId: Long, cafeId: Long, resource: CafeMenuUpdateRequest) {
val cafeMenu = cafeMenuRepository.findByIdOrNull(menuId)
?: throw CafeMenuNotFoundException(menuId = menuId, cafeId = cafeId)
@@ -31,7 +31,6 @@ class CafeMenuService(
menuOptionService.bulkUpdate(resource.menuOptionList)
}
@Transactional
fun deleteByCafeMenuId(menuId: Long, cafeId: Long) {
val cafeMenu = cafeMenuRepository.findByIdOrNull(menuId)
?: throw CafeMenuNotFoundException(menuId = menuId, cafeId = cafeId)
@@ -39,7 +38,6 @@ class CafeMenuService(
cafeMenuRepository.delete(cafeMenu)
}
@Transactional
fun bulkDelete(cafeId: Long, cafeMenuIdList: List<Long>) {
cafeMenuIdList.forEach {
deleteByCafeMenuId(menuId = it, cafeId = cafeId)

View File

@@ -1,57 +1,96 @@
package io.beaniejoy.dongnecafe.domain.cafe.service
import io.beaniejoy.dongnecafe.domain.cafe.entity.Cafe
import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeMenuUpdateRequest
import io.beaniejoy.dongnecafe.domain.cafe.entity.CafeMenu
import io.beaniejoy.dongnecafe.domain.cafe.error.CafeMenuNotFoundException
import io.beaniejoy.dongnecafe.domain.cafe.repository.CafeMenuRepository
import io.beaniejoy.dongnecafe.domain.cafe.repository.CafeRepository
import io.beaniejoy.dongnecafe.domain.cafe.utils.CafeTestUtils
import org.junit.jupiter.api.BeforeEach
import io.beaniejoy.dongnecafe.domain.cafe.repository.MenuOptionRepository
import io.beaniejoy.dongnecafe.domain.cafe.repository.OptionDetailRepository
import io.beaniejoy.dongnecafe.domain.cafe.utils.CafeMenuTestUtils
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.annotation.Rollback
import org.springframework.transaction.annotation.Transactional
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.junit.jupiter.MockitoExtension
import java.util.*
@SpringBootTest
@ExtendWith(MockitoExtension::class)
internal class CafeMenuServiceTest {
@Autowired
lateinit var cafeMenuRepository: CafeMenuRepository
@Autowired
lateinit var cafeRepository: CafeRepository
@Autowired
lateinit var cafeMenuService: CafeMenuService
@Mock
lateinit var mockCafeMenuRepository: CafeMenuRepository
@BeforeEach
fun setup() {
val cafeRegisterRequest = CafeTestUtils.createCafeRegisterRequest()
@Mock
lateinit var mockMenuOptionRepository: MenuOptionRepository
cafeRepository.save(
Cafe.createCafe(
name = cafeRegisterRequest.name!!,
address = cafeRegisterRequest.address!!,
phoneNumber = cafeRegisterRequest.phoneNumber!!,
description = cafeRegisterRequest.description!!,
cafeMenuRequestList = cafeRegisterRequest.cafeMenuList
)
@Mock
lateinit var mockOptionDetailRepository: OptionDetailRepository
@Mock
lateinit var mockOptionDetailService: OptionDetailService
@Mock
lateinit var mockMenuOptionService: MenuOptionService
@InjectMocks
lateinit var mockCafeMenuService: CafeMenuService
@Test
@DisplayName("카페 메뉴 ID를 통한 카페 메뉴 상세 조회")
fun find_cafe_menu_by_cafe_menu_id() {
// given
val (name, price, menuOptionList) = CafeMenuTestUtils.createCafeMenuRegisterRequest()
val cafeMenu = CafeMenu.createCafeMenu(
name = name!!,
price = price,
menuOptionRequestList = menuOptionList
)
val findCafeId = 100L
val findCafeMenuId = 1001L
`when`(mockCafeMenuRepository.findById(findCafeMenuId))
.thenReturn(Optional.of(cafeMenu.apply {
// cafe_menu_id Reflection 주입
CafeMenuTestUtils.injectCafeMenuId(this, findCafeMenuId)
}))
// when
val cafeMenuDetailedInfo = mockCafeMenuService.getDetailedInfoByMenuId(findCafeMenuId, findCafeId)
// then
verify(mockCafeMenuRepository).findById(findCafeMenuId)
cafeMenuDetailedInfo.also {
assertEquals(findCafeMenuId, it.cafeMenuId)
assertEquals(name, it.name)
assertEquals(price, it.price)
// TODO: MenuOption list도 비교 검증해야되는지
}
}
@Test
@Transactional
@Rollback(false)
fun updateTest() {
val cafeMenu = cafeRepository.findByName("beanie_cafe")!!.cafeMenuList[0]
@DisplayName("존재하지 않는 카페 조회에 대한 예외 발생 테스트")
fun find_cafe_menu_by_cafe_menu_id_when_not_existed() {
// given
val findCafeId = 100L
val findCafeMenuId = 1001L
`when`(mockCafeMenuRepository.findById(findCafeMenuId)).thenReturn(Optional.empty())
cafeMenuService.updateInfoAndBulkUpdate(
menuId = cafeMenu.id,
cafeId = cafeMenu.cafe!!.id,
resource = CafeMenuUpdateRequest(name = "updated_name", price = cafeMenu.price)
)
}
// then
val exception = assertThrows<CafeMenuNotFoundException> {
// when
mockCafeMenuService.getDetailedInfoByMenuId(findCafeMenuId, findCafeId)
}
@Test
@Transactional
fun deleteTest() {
cafeMenuRepository.deleteById(100L)
assertEquals("Cafe[${findCafeId}]의 Menu[${findCafeMenuId}]는 존재하지 않는 메뉴입니다.", exception.message)
verify(mockCafeMenuRepository).findById(findCafeMenuId)
}
}
}

View File

@@ -15,6 +15,7 @@ import org.mockito.junit.jupiter.MockitoExtension
import java.util.*
import javax.persistence.GeneratedValue
// TODO: BDD 스타일로 리팩토링 해볼 것(추후 mockK도 사용해보자)
@ExtendWith(MockitoExtension::class)
@TestMethodOrder(MethodOrderer.DisplayName::class)
internal class CafeServiceTest {
@@ -28,25 +29,25 @@ internal class CafeServiceTest {
@DisplayName("카페 신규 생성 테스트")
fun create_cafe_test() {
// given
val cafeRequestDto = CafeTestUtils.createCafeRegisterRequest()
val (name, address, phoneNumber, description, cafeMenuList) = CafeTestUtils.createCafeRegisterRequest()
val savedMockCafeId = 100L
`when`(mockCafeRepository.findByName(cafeRequestDto.name!!)).thenReturn(null)
`when`(mockCafeRepository.findByName(name!!)).thenReturn(null)
`when`(mockCafeRepository.save(any(Cafe::class.java))).thenAnswer {
injectCafeId(it.getArgument(0), savedMockCafeId)
CafeTestUtils.injectCafeId(it.getArgument(0), savedMockCafeId)
}
// when
val savedCafeId = mockCafeService.createNew(
name = cafeRequestDto.name!!,
address = cafeRequestDto.address!!,
phoneNumber = cafeRequestDto.phoneNumber!!,
description = cafeRequestDto.description!!,
cafeMenuRequestList = cafeRequestDto.cafeMenuList
name = name,
address = address!!,
phoneNumber = phoneNumber!!,
description = description!!,
cafeMenuRequestList = cafeMenuList
)
// then
verify(mockCafeRepository).findByName(cafeRequestDto.name!!) // TODO eq 에러 발생 이유
verify(mockCafeRepository).findByName(name) // TODO eq 에러 발생 이유
verify(mockCafeRepository).save(any(Cafe::class.java))
assertEquals(savedCafeId, savedMockCafeId)
@@ -56,61 +57,74 @@ internal class CafeServiceTest {
@DisplayName("카페 신규 생성시 이미 존재하는 카페 예외 발생 테스트")
fun fail_create_cafe_when_existed() {
// given
val cafeRequestDto = CafeTestUtils.createCafeRegisterRequest()
val (name, address, phoneNumber, description, cafeMenuList) = CafeTestUtils.createCafeRegisterRequest()
val cafe = Cafe.createCafe(
name = cafeRequestDto.name!!,
address = cafeRequestDto.address!!,
phoneNumber = cafeRequestDto.phoneNumber!!,
description = cafeRequestDto.description!!,
cafeMenuRequestList = cafeRequestDto.cafeMenuList
name = name!!,
address = address!!,
phoneNumber = phoneNumber!!,
description = description!!,
cafeMenuRequestList = cafeMenuList
)
`when`(mockCafeRepository.findByName(cafeRequestDto.name!!)).thenReturn(cafe)
`when`(mockCafeRepository.findByName(name)).thenReturn(cafe)
// then
assertThrows<CafeExistedException> {
// when
mockCafeService.createNew(
name = cafeRequestDto.name!!,
address = cafeRequestDto.address!!,
phoneNumber = cafeRequestDto.phoneNumber!!,
description = cafeRequestDto.description!!,
cafeMenuRequestList = cafeRequestDto.cafeMenuList
name = name,
address = address,
phoneNumber = phoneNumber,
description = description,
cafeMenuRequestList = cafeMenuList
)
}
verify(mockCafeRepository).findByName(cafeRequestDto.name!!)
verify(mockCafeRepository).findByName(name)
}
@Test
@DisplayName("카페 정보 변경 테스트")
fun update_cafe_test() {
// given
val cafeRequestDto = CafeTestUtils.createCafeRegisterRequest()
val (name, address, phoneNumber, description, cafeMenuList) = CafeTestUtils.createCafeRegisterRequest()
val cafe = Cafe.createCafe(
name = cafeRequestDto.name!!,
address = cafeRequestDto.address!!,
phoneNumber = cafeRequestDto.phoneNumber!!,
description = cafeRequestDto.description!!,
cafeMenuRequestList = cafeRequestDto.cafeMenuList
name = name!!,
address = address!!,
phoneNumber = phoneNumber!!,
description = description!!,
cafeMenuRequestList = cafeMenuList
)
val cafeId = 50L
// TODO findByIdOrNull은 kotlin test 라이브러리 필요한 듯
`when`(mockCafeRepository.findById(cafeId)).thenReturn(Optional.of(cafe))
val mockCafe = mock(Cafe::class.java)
`when`(mockCafeRepository.findById(cafeId)).thenReturn(Optional.of(mockCafe))
// then
mockCafeService.updateInfo(
id = cafeId,
name = "",
address = "",
phoneNumber = "",
description = "",
doNothing().`when`(mockCafe).updateInfo(
name = anyString(),
address = anyString(),
phoneNumber = anyString(),
description = anyString()
)
verify(mockCafeRepository).findById(eq(cafeId))
// when
mockCafeService.updateInfo(
id = cafeId,
name = "updated_name",
address = "updated_address",
phoneNumber = "updated_phoneNumber",
description = "updated_desc"
)
// TODO update TEST 방법?
// then
verify(mockCafeRepository).findById(eq(cafeId))
verify(mockCafe).updateInfo(
name = "updated_name",
address = "updated_address",
phoneNumber = "updated_phoneNumber",
description = "updated_desc"
)
}
@Test
@@ -131,19 +145,4 @@ internal class CafeServiceTest {
)
}
}
private fun injectCafeId(
cafe: Cafe,
newCafeId: Long,
): Cafe {
val idField = cafe.javaClass.declaredFields
.find { f ->
f.getAnnotation(GeneratedValue::class.java) != null
} ?: return cafe
idField.isAccessible = true
idField.set(cafe, newCafeId)
return cafe
}
}

View File

@@ -0,0 +1,98 @@
package io.beaniejoy.dongnecafe.domain.cafe.utils
import io.beaniejoy.dongnecafe.domain.cafe.entity.CafeMenu
import io.beaniejoy.dongnecafe.domain.cafe.entity.MenuOption
import io.beaniejoy.dongnecafe.domain.cafe.entity.OptionDetail
import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeMenuRegisterRequest
import io.beaniejoy.dongnecafe.domain.cafe.model.request.MenuOptionRegisterRequest
import io.beaniejoy.dongnecafe.domain.cafe.model.request.OptionDetailRegisterRequest
import org.junit.jupiter.api.Assertions
import java.math.BigDecimal
import javax.persistence.GeneratedValue
class CafeMenuTestUtils {
companion object {
fun createCafeMenuRegisterRequest(): CafeMenuRegisterRequest {
return createCafeMenuRegisterRequestList()[0]
}
fun createCafeMenuRegisterRequestList(): List<CafeMenuRegisterRequest> {
val sizeOptionDetailList = listOf(
OptionDetailRegisterRequest(name = "medium", extraPrice = BigDecimal.ZERO),
OptionDetailRegisterRequest(name = "large", extraPrice = BigDecimal.valueOf(200L)),
OptionDetailRegisterRequest(name = "venti", extraPrice = BigDecimal.valueOf(700L))
)
val sizeMenuOption = MenuOptionRegisterRequest(
title = "size",
optionDetailList = sizeOptionDetailList
)
return listOf(
CafeMenuRegisterRequest(
name = "menu1",
price = BigDecimal.valueOf(2_800L),
menuOptionList = listOf(sizeMenuOption)
),
CafeMenuRegisterRequest(
name = "menu2",
price = BigDecimal.valueOf(3_500L),
menuOptionList = listOf(sizeMenuOption)
),
)
}
fun assertCafeMenuListEquals(
cafeMenuRequestList: List<CafeMenuRegisterRequest>,
cafeMenuList: List<CafeMenu>,
) {
for (index in cafeMenuRequestList.indices) {
Assertions.assertEquals(cafeMenuRequestList[index].name, cafeMenuList[index].name)
Assertions.assertEquals(cafeMenuRequestList[index].price, cafeMenuList[index].price)
assertMenuOptionListEquals(
cafeMenuRequestList[index].menuOptionList,
cafeMenuList[index].menuOptionList
)
}
}
private fun assertMenuOptionListEquals(
menuOptionRequestList: List<MenuOptionRegisterRequest>,
menuOptionList: List<MenuOption>,
) {
for (index in menuOptionRequestList.indices) {
Assertions.assertEquals(menuOptionRequestList[index].title, menuOptionList[index].title)
assertOptionDetailListEquals(
menuOptionRequestList[index].optionDetailList,
menuOptionList[index].optionDetailList
)
}
}
private fun assertOptionDetailListEquals(
optionDetailRequestList: List<OptionDetailRegisterRequest>,
optionDetailList: MutableList<OptionDetail>,
) {
for (index in optionDetailRequestList.indices) {
Assertions.assertEquals(optionDetailRequestList[index].name, optionDetailList[index].name)
Assertions.assertEquals(optionDetailRequestList[index].extraPrice, optionDetailList[index].extraPrice)
}
}
fun injectCafeMenuId(
cafeMenu: CafeMenu,
newCafeMenuId: Long,
): CafeMenu {
val idField = cafeMenu.javaClass.declaredFields
.find { f ->
f.getAnnotation(GeneratedValue::class.java) != null
} ?: return cafeMenu
idField.isAccessible = true
idField.set(cafeMenu, newCafeMenuId)
return cafeMenu
}
}
}

View File

@@ -10,6 +10,7 @@ import io.beaniejoy.dongnecafe.domain.cafe.entity.MenuOption
import io.beaniejoy.dongnecafe.domain.cafe.entity.OptionDetail
import org.junit.jupiter.api.Assertions.*
import java.math.BigDecimal
import javax.persistence.GeneratedValue
class CafeTestUtils {
companion object {
@@ -19,46 +20,7 @@ class CafeTestUtils {
assertEquals(request.phoneNumber, entity.phoneNumber)
assertEquals(request.description, entity.description)
assertCafeMenuListEquals(request.cafeMenuList, entity.cafeMenuList)
}
private fun assertCafeMenuListEquals(
cafeMenuRequestList: List<CafeMenuRegisterRequest>,
cafeMenuList: List<CafeMenu>,
) {
for (index in cafeMenuRequestList.indices) {
assertEquals(cafeMenuRequestList[index].name, cafeMenuList[index].name)
assertEquals(cafeMenuRequestList[index].price, cafeMenuList[index].price)
assertMenuOptionListEquals(
cafeMenuRequestList[index].menuOptionList,
cafeMenuList[index].menuOptionList
)
}
}
private fun assertMenuOptionListEquals(
menuOptionRequestList: List<MenuOptionRegisterRequest>,
menuOptionList: List<MenuOption>,
) {
for (index in menuOptionRequestList.indices) {
assertEquals(menuOptionRequestList[index].title, menuOptionList[index].title)
assertOptionDetailListEquals(
menuOptionRequestList[index].optionDetailList,
menuOptionList[index].optionDetailList
)
}
}
private fun assertOptionDetailListEquals(
optionDetailRequestList: List<OptionDetailRegisterRequest>,
optionDetailList: MutableList<OptionDetail>,
) {
for (index in optionDetailRequestList.indices) {
assertEquals(optionDetailRequestList[index].name, optionDetailList[index].name)
assertEquals(optionDetailRequestList[index].extraPrice, optionDetailList[index].extraPrice)
}
CafeMenuTestUtils.assertCafeMenuListEquals(request.cafeMenuList, entity.cafeMenuList)
}
fun createCafeRegisterRequest(): CafeRegisterRequest {
@@ -67,36 +29,28 @@ class CafeTestUtils {
val phoneNumber = "01012345678"
val description = "beanie_cafe_description"
val sizeOptionDetailList = listOf(
OptionDetailRegisterRequest(name = "medium", extraPrice = BigDecimal.ZERO),
OptionDetailRegisterRequest(name = "large", extraPrice = BigDecimal.valueOf(200L)),
OptionDetailRegisterRequest(name = "venti", extraPrice = BigDecimal.valueOf(700L))
)
val sizeMenuOption = MenuOptionRegisterRequest(
title = "size",
optionDetailList = sizeOptionDetailList
)
val cafeMenuList = listOf(
CafeMenuRegisterRequest(
name = "menu1",
price = BigDecimal.valueOf(2_800L),
menuOptionList = listOf(sizeMenuOption)
),
CafeMenuRegisterRequest(
name = "menu2",
price = BigDecimal.valueOf(3_500L),
menuOptionList = listOf(sizeMenuOption)
),
)
return CafeRegisterRequest(
name = cafeName,
address = cafeAddress,
phoneNumber = phoneNumber,
description = description,
cafeMenuList = cafeMenuList
cafeMenuList = CafeMenuTestUtils.createCafeMenuRegisterRequestList()
)
}
fun injectCafeId(
cafe: Cafe,
newCafeId: Long,
): Cafe {
val idField = cafe.javaClass.declaredFields
.find { f ->
f.getAnnotation(GeneratedValue::class.java) != null
} ?: return cafe
idField.isAccessible = true
idField.set(cafe, newCafeId)
return cafe
}
}
}