Merge pull request #10 from beaniejoy/feature/8
cafe 관련 기본 기능 추가 및 수정(기본 CRUD 구성) & 기본적인 테스트코드 구성
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -33,4 +33,4 @@ out/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
.vscode/
|
||||
@@ -11,16 +11,20 @@ import javax.persistence.MappedSuperclass
|
||||
|
||||
@MappedSuperclass
|
||||
@EntityListeners(AuditingEntityListener::class)
|
||||
class BaseTimeEntity(
|
||||
abstract class BaseTimeEntity protected constructor() {
|
||||
@CreatedDate
|
||||
val createdAt: LocalDateTime = LocalDateTime.now(),
|
||||
var createdAt: LocalDateTime = LocalDateTime.now()
|
||||
protected set
|
||||
|
||||
@CreatedBy
|
||||
val createdBy: String = "",
|
||||
var createdBy: String = ""
|
||||
protected set
|
||||
|
||||
@LastModifiedDate
|
||||
val updatedAt: LocalDateTime? = null,
|
||||
var updatedAt: LocalDateTime? = null
|
||||
protected set
|
||||
|
||||
@LastModifiedBy
|
||||
val updatedBy: String? = null
|
||||
)
|
||||
var updatedBy: String? = null
|
||||
protected set
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package io.beaniejoy.dongnecafe.domain.cafe.controller
|
||||
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.dto.cafe.CafeInfoResponseDto
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.dto.cafe.CafeSearchResponseDto
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.dto.cafe.CafeUpdateRequestDto
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.dto.request.CafeInfoRequestDto
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.service.CafeService
|
||||
import org.springframework.data.domain.Page
|
||||
import org.springframework.data.domain.Pageable
|
||||
@@ -15,8 +15,19 @@ import org.springframework.web.bind.annotation.*
|
||||
class CafeController(
|
||||
private val cafeService: CafeService
|
||||
) {
|
||||
@PostMapping
|
||||
fun createCafe(@RequestBody resource: CafeInfoRequestDto): Long {
|
||||
return cafeService.createCafe(
|
||||
name = resource.name!!,
|
||||
address = resource.address!!,
|
||||
phoneNumber = resource.phoneNumber!!,
|
||||
description = resource.description!!,
|
||||
cafeMenuRequestList = resource.cafeMenuList
|
||||
)
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
fun searchCafeList(
|
||||
fun searchCafe(
|
||||
@PageableDefault(sort = ["name"], direction = Sort.Direction.ASC, page = 0, size = 10) pageable: Pageable
|
||||
): Page<CafeSearchResponseDto> {
|
||||
return cafeService.getCafeList(pageable)
|
||||
@@ -31,7 +42,7 @@ class CafeController(
|
||||
@PutMapping("/{id}")
|
||||
fun updateCafeInfo(
|
||||
@PathVariable("id") id: Long,
|
||||
@RequestBody resource: CafeUpdateRequestDto
|
||||
@RequestBody resource: CafeInfoRequestDto
|
||||
): String {
|
||||
cafeService.updateCafe(
|
||||
id = id,
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package io.beaniejoy.dongnecafe.domain.cafe.dto.cafe
|
||||
|
||||
data class CafeUpdateRequestDto(
|
||||
val name: String? = null,
|
||||
val address: String? = null,
|
||||
val phoneNumber: String? = null,
|
||||
val description: String? = null
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.beaniejoy.dongnecafe.domain.cafe.dto.request
|
||||
|
||||
data class CafeInfoRequestDto(
|
||||
val name: String? = null,
|
||||
val address: String? = null,
|
||||
val phoneNumber: String? = null,
|
||||
val description: String? = null,
|
||||
val cafeMenuList: List<CafeMenuInfoRequestDto> = arrayListOf()
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.beaniejoy.dongnecafe.domain.cafe.dto.request
|
||||
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class CafeMenuInfoRequestDto(
|
||||
val name: String? = null,
|
||||
val price: BigDecimal = BigDecimal.ZERO,
|
||||
val menuOptionList: List<MenuOptionInfoRequestDto>
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
package io.beaniejoy.dongnecafe.domain.cafe.dto.request
|
||||
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class MenuOptionInfoRequestDto(
|
||||
val title: String,
|
||||
val optionDetailList: List<OptionDetailInfoRequestDto>
|
||||
)
|
||||
|
||||
data class OptionDetailInfoRequestDto(
|
||||
val name: String,
|
||||
val extraPrice: BigDecimal
|
||||
)
|
||||
@@ -1,37 +1,84 @@
|
||||
package io.beaniejoy.dongnecafe.domain.cafe.entity
|
||||
|
||||
import io.beaniejoy.dongnecafe.common.entity.BaseTimeEntity
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.dto.request.CafeMenuInfoRequestDto
|
||||
import javax.persistence.*
|
||||
|
||||
@Entity
|
||||
@Table(name = "cafe")
|
||||
class Cafe(
|
||||
class Cafe protected constructor(
|
||||
name: String,
|
||||
address: String,
|
||||
phoneNumber: String,
|
||||
description: String,
|
||||
) : BaseTimeEntity() {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
val id: Long = 0L,
|
||||
val id: Long = 0L
|
||||
|
||||
@Column(name = "name", nullable = false)
|
||||
var name: String,
|
||||
var name: String = name
|
||||
protected set
|
||||
|
||||
@Column(name = "address", nullable = false)
|
||||
var address: String,
|
||||
var address: String = address
|
||||
protected set
|
||||
|
||||
@Column(name = "phone_number", nullable = false)
|
||||
var phoneNumber: String,
|
||||
var phoneNumber: String = phoneNumber
|
||||
protected set
|
||||
|
||||
@Column(name = "total_rate", nullable = false)
|
||||
val totalRate: Double,
|
||||
val totalRate: Double = 0.0
|
||||
|
||||
@Column(name = "description", nullable = false)
|
||||
var description: String,
|
||||
var description: String = description
|
||||
protected set
|
||||
|
||||
@OneToMany(mappedBy = "cafe", fetch = FetchType.LAZY)
|
||||
val cafeMenuList: MutableList<CafeMenu>,
|
||||
@OneToMany(mappedBy = "cafe", fetch = FetchType.LAZY, cascade = [CascadeType.ALL])
|
||||
val cafeMenuList: MutableList<CafeMenu> = arrayListOf()
|
||||
|
||||
@OneToMany(mappedBy = "cafe", fetch = FetchType.LAZY)
|
||||
val cafeImageList: MutableList<CafeImage>
|
||||
) : BaseTimeEntity() {
|
||||
fun updateInfo(name: String, address: String, phoneNumber: String, description: String) {
|
||||
@OneToMany(mappedBy = "cafe", fetch = FetchType.LAZY, cascade = [CascadeType.ALL])
|
||||
val cafeImageList: MutableList<CafeImage> = arrayListOf()
|
||||
|
||||
companion object {
|
||||
fun createCafe(
|
||||
name: String,
|
||||
address: String,
|
||||
phoneNumber: String,
|
||||
description: String,
|
||||
cafeMenuRequestList: List<CafeMenuInfoRequestDto>,
|
||||
): Cafe {
|
||||
val cafeMenuEntityList = cafeMenuRequestList.map { cafeMenuRequestDto ->
|
||||
CafeMenu.createCafeMenu(
|
||||
name = cafeMenuRequestDto.name!!,
|
||||
price = cafeMenuRequestDto.price,
|
||||
menuOptionRequestList = cafeMenuRequestDto.menuOptionList
|
||||
)
|
||||
}
|
||||
|
||||
return Cafe(
|
||||
name = name,
|
||||
address = address,
|
||||
phoneNumber = phoneNumber,
|
||||
description = description
|
||||
).apply {
|
||||
cafeMenuEntityList.forEach { this.addCafeMenu(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addCafeMenu(cafeMenu: CafeMenu) {
|
||||
this.cafeMenuList.add(cafeMenu)
|
||||
cafeMenu.updateCafe(this)
|
||||
}
|
||||
|
||||
fun updateInfo(
|
||||
name: String,
|
||||
address: String,
|
||||
phoneNumber: String,
|
||||
description: String,
|
||||
) {
|
||||
this.name = name
|
||||
this.address = address
|
||||
this.phoneNumber = phoneNumber
|
||||
|
||||
@@ -1,26 +1,58 @@
|
||||
package io.beaniejoy.dongnecafe.domain.cafe.entity
|
||||
|
||||
import io.beaniejoy.dongnecafe.common.entity.BaseTimeEntity
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.dto.request.MenuOptionInfoRequestDto
|
||||
import java.math.BigDecimal
|
||||
import javax.persistence.*
|
||||
|
||||
@Entity
|
||||
@Table(name = "cafe_menu")
|
||||
class CafeMenu(
|
||||
class CafeMenu protected constructor(
|
||||
name: String,
|
||||
price: BigDecimal,
|
||||
) : BaseTimeEntity() {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
val id: Long = 0L,
|
||||
val id: Long = 0L
|
||||
|
||||
@Column(name = "name", nullable = false)
|
||||
val name: String,
|
||||
val name: String = name
|
||||
|
||||
@Column(name = "price", nullable = false)
|
||||
val price: BigDecimal = BigDecimal.ZERO,
|
||||
val price: BigDecimal = price
|
||||
|
||||
@ManyToOne
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "cafe_id", nullable = false)
|
||||
val cafe: Cafe,
|
||||
var cafe: Cafe? = null
|
||||
protected set
|
||||
|
||||
@OneToMany(mappedBy = "cafeMenu", fetch = FetchType.LAZY)
|
||||
val menuOptionList: MutableList<MenuOption>
|
||||
) : BaseTimeEntity()
|
||||
@OneToMany(mappedBy = "cafeMenu", fetch = FetchType.LAZY, cascade = [CascadeType.ALL])
|
||||
val menuOptionList: MutableList<MenuOption> = arrayListOf()
|
||||
|
||||
companion object {
|
||||
fun createCafeMenu(name: String, price: BigDecimal, menuOptionRequestList: List<MenuOptionInfoRequestDto>): CafeMenu {
|
||||
val menuOptionEntityList = menuOptionRequestList.map { menuOptionRequestDto ->
|
||||
MenuOption.createMenuOption(
|
||||
title = menuOptionRequestDto.title,
|
||||
optionDetailRequestList = menuOptionRequestDto.optionDetailList
|
||||
)
|
||||
}
|
||||
|
||||
return CafeMenu(
|
||||
name = name,
|
||||
price = price
|
||||
).apply {
|
||||
menuOptionEntityList.forEach { this.addMenuOption(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateCafe(cafe: Cafe) {
|
||||
this.cafe = cafe
|
||||
}
|
||||
|
||||
fun addMenuOption(menuOption: MenuOption) {
|
||||
this.menuOptionList.add(menuOption)
|
||||
menuOption.updateCafeMenu(this)
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,52 @@
|
||||
package io.beaniejoy.dongnecafe.domain.cafe.entity
|
||||
|
||||
import io.beaniejoy.dongnecafe.common.entity.BaseTimeEntity
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.dto.request.OptionDetailInfoRequestDto
|
||||
import javax.persistence.*
|
||||
|
||||
@Entity
|
||||
@Table(name = "menu_option")
|
||||
class MenuOption(
|
||||
class MenuOption protected constructor(
|
||||
title: String
|
||||
) : BaseTimeEntity() {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
val id: Long = 0L,
|
||||
val id: Long = 0L
|
||||
|
||||
@Column(name = "title", nullable = false)
|
||||
val title: String,
|
||||
val title: String = title
|
||||
|
||||
@ManyToOne
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "menu_id", nullable = false)
|
||||
val cafeMenu: CafeMenu,
|
||||
var cafeMenu: CafeMenu? = null
|
||||
protected set
|
||||
|
||||
@OneToMany(mappedBy = "menuOption", fetch = FetchType.EAGER)
|
||||
val optionDetailList: MutableList<OptionDetail>
|
||||
) : BaseTimeEntity()
|
||||
@OneToMany(mappedBy = "menuOption", fetch = FetchType.EAGER, cascade = [CascadeType.ALL])
|
||||
val optionDetailList: MutableList<OptionDetail> = arrayListOf()
|
||||
|
||||
companion object {
|
||||
fun createMenuOption(title: String, optionDetailRequestList: List<OptionDetailInfoRequestDto>): MenuOption {
|
||||
val optionDetailEntityList = optionDetailRequestList.map { optionDetailRequestDto ->
|
||||
OptionDetail.createOptionDetail(
|
||||
name = optionDetailRequestDto.name,
|
||||
extraPrice = optionDetailRequestDto.extraPrice
|
||||
)
|
||||
}
|
||||
|
||||
return MenuOption(
|
||||
title = title
|
||||
).apply {
|
||||
optionDetailEntityList.forEach { this.addOptionDetail(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateCafeMenu(cafeMenu: CafeMenu) {
|
||||
this.cafeMenu = cafeMenu
|
||||
}
|
||||
|
||||
fun addOptionDetail(optionDetail: OptionDetail) {
|
||||
this.optionDetailList.add(optionDetail)
|
||||
optionDetail.updateMenuOption(this)
|
||||
}
|
||||
}
|
||||
@@ -6,18 +6,35 @@ import javax.persistence.*
|
||||
|
||||
@Entity
|
||||
@Table(name = "option_detail")
|
||||
class OptionDetail(
|
||||
class OptionDetail protected constructor(
|
||||
name: String,
|
||||
extraPrice: BigDecimal
|
||||
) : BaseTimeEntity() {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
val id: Long = 0L,
|
||||
val id: Long = 0L
|
||||
|
||||
@Column(name = "name", nullable = false)
|
||||
val name: String,
|
||||
val name: String = name
|
||||
|
||||
@Column(name = "extra_price", nullable = false)
|
||||
val extraPrice: BigDecimal,
|
||||
val extraPrice: BigDecimal = extraPrice
|
||||
|
||||
@ManyToOne
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "option_id", nullable = false)
|
||||
val menuOption: MenuOption
|
||||
): BaseTimeEntity()
|
||||
var menuOption: MenuOption? = null
|
||||
protected set
|
||||
|
||||
companion object {
|
||||
fun createOptionDetail(name: String, extraPrice: BigDecimal): OptionDetail {
|
||||
return OptionDetail(
|
||||
name = name,
|
||||
extraPrice = extraPrice
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateMenuOption(menuOption: MenuOption) {
|
||||
this.menuOption = menuOption
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package io.beaniejoy.dongnecafe.domain.cafe.error
|
||||
|
||||
class CafeExistedException(name: String): RuntimeException("Cafe[$name] is already existed")
|
||||
@@ -4,4 +4,5 @@ import io.beaniejoy.dongnecafe.domain.cafe.entity.Cafe
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
|
||||
interface CafeRepository : JpaRepository<Cafe, Long> {
|
||||
fun findByName(name: String): Cafe?
|
||||
}
|
||||
@@ -2,7 +2,12 @@ package io.beaniejoy.dongnecafe.domain.cafe.service
|
||||
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.dto.cafe.CafeInfoResponseDto
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.dto.cafe.CafeSearchResponseDto
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.dto.request.CafeMenuInfoRequestDto
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.entity.Cafe
|
||||
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.error.CafeExistedException
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.error.CafeNotFoundException
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.repository.CafeRepository
|
||||
import mu.KLogging
|
||||
@@ -13,20 +18,56 @@ import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
@Transactional(readOnly = true)
|
||||
class CafeService(
|
||||
private val cafeRepository: CafeRepository
|
||||
private val cafeRepository: CafeRepository,
|
||||
) {
|
||||
companion object: KLogging()
|
||||
companion object : KLogging()
|
||||
|
||||
/**
|
||||
* 카페 생성 로직
|
||||
* - 카페 생성시 카페정보 뿐만 아니라 하위 메뉴정보, 옵션, 옵션상세 같이 생성
|
||||
* - 카페 정보(이름, 주소, 전화번호, 소개글)
|
||||
* - 카페 메뉴정보 (메뉴 이름, 가격 /ex. 아메리카노, 2,800)
|
||||
* - 메뉴 옵션 (옵션 이름 /ex. 사이즈)
|
||||
* - 옵션 상세 (상세 이름, 추가 금액 /ex. [(medium, 0), (large, 200), (venti, 700)])
|
||||
*/
|
||||
@Transactional
|
||||
fun createCafe(
|
||||
name: String,
|
||||
address: String,
|
||||
phoneNumber: String,
|
||||
description: String,
|
||||
cafeMenuRequestList: List<CafeMenuInfoRequestDto>,
|
||||
): Long {
|
||||
checkCafeExistedByName(name)
|
||||
|
||||
val cafe = Cafe.createCafe(
|
||||
name = name,
|
||||
address = address,
|
||||
phoneNumber = phoneNumber,
|
||||
description = description,
|
||||
cafeMenuRequestList = cafeMenuRequestList
|
||||
)
|
||||
|
||||
val savedCafe = cafeRepository.save(cafe)
|
||||
|
||||
return savedCafe.id
|
||||
}
|
||||
|
||||
private fun checkCafeExistedByName(name: String) {
|
||||
val findCafe = cafeRepository.findByName(name)
|
||||
if (findCafe != null) {
|
||||
throw CafeExistedException(name)
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun getCafeList(pageable: Pageable): Page<CafeSearchResponseDto> {
|
||||
val cafeList: Page<Cafe> = cafeRepository.findAll(pageable)
|
||||
|
||||
return cafeList.map { CafeSearchResponseDto.of(it) }
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun getCafeInfoByCafeId(id: Long): CafeInfoResponseDto {
|
||||
val cafe = cafeRepository.findByIdOrNull(id)
|
||||
?: throw CafeNotFoundException(id)
|
||||
@@ -34,6 +75,11 @@ class CafeService(
|
||||
return CafeInfoResponseDto.of(cafe)
|
||||
}
|
||||
|
||||
/**
|
||||
* 카페 정보 수정
|
||||
* - 카페 정보만 수정 (하위 엔티티에 대해서는 각 도메인 영역에서 수정)
|
||||
*/
|
||||
@Transactional
|
||||
fun updateCafe(
|
||||
id: Long,
|
||||
name: String,
|
||||
|
||||
@@ -11,8 +11,13 @@ spring:
|
||||
hibernate:
|
||||
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
|
||||
format_sql: true
|
||||
show-sql: true
|
||||
show-sql: false
|
||||
flyway:
|
||||
baseline-on-migrate: true
|
||||
locations: classpath:db/migration,classpath:db/seed
|
||||
# baseline-version: 0
|
||||
|
||||
logging:
|
||||
level:
|
||||
org.hibernate.SQL: debug # logger 통해 로깅
|
||||
# org.hibernate.type: trace
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package io.beaniejoy.dongnecafe.domain.cafe.entity
|
||||
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.utils.CafeTestUtils
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
internal class CafeTest {
|
||||
@Test
|
||||
fun create_cafe_test() {
|
||||
val cafeRequestDto = CafeTestUtils.createCafeRequestDto()
|
||||
|
||||
val cafe = Cafe.createCafe(
|
||||
name = cafeRequestDto.name!!,
|
||||
address = cafeRequestDto.address!!,
|
||||
phoneNumber = cafeRequestDto.phoneNumber!!,
|
||||
description = cafeRequestDto.description!!,
|
||||
cafeMenuRequestList = cafeRequestDto.cafeMenuList
|
||||
)
|
||||
|
||||
CafeTestUtils.assertCafeEquals(request = cafeRequestDto, entity = cafe)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package io.beaniejoy.dongnecafe.domain.cafe.repository
|
||||
|
||||
import io.beaniejoy.dongnecafe.common.config.AuditingConfig
|
||||
import io.beaniejoy.dongnecafe.common.entity.BaseEntityAuditorAware
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.entity.Cafe
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.utils.CafeTestUtils
|
||||
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.autoconfigure.orm.jpa.DataJpaTest
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
import org.springframework.context.annotation.FilterType
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
|
||||
@DataJpaTest(
|
||||
includeFilters = [
|
||||
ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = [AuditingConfig::class]),
|
||||
ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = [BaseEntityAuditorAware::class])
|
||||
]
|
||||
)
|
||||
internal class CafeRepositoryTest {
|
||||
@Autowired
|
||||
lateinit var cafeRepository: CafeRepository
|
||||
|
||||
@Test
|
||||
@DisplayName("[JPA] 신규 Cafe save 테스트")
|
||||
fun save_cafe_test() {
|
||||
val cafeRequestDto = CafeTestUtils.createCafeRequestDto()
|
||||
val cafe = cafeRequestDto.let {
|
||||
Cafe.createCafe(
|
||||
name = it.name!!,
|
||||
address = it.address!!,
|
||||
phoneNumber = it.phoneNumber!!,
|
||||
description = it.description!!,
|
||||
cafeMenuRequestList = it.cafeMenuList
|
||||
)
|
||||
}
|
||||
|
||||
val savedCafe = cafeRepository.save(cafe)
|
||||
|
||||
assertEquals(1L, savedCafe.id)
|
||||
CafeTestUtils.assertCafeEquals(cafeRequestDto, savedCafe)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("[JPA] 기존 Cafe 정보 update 테스트")
|
||||
fun update_cafe_test() {
|
||||
// TODO 테스트용 카페 데이터 주입 구성하기
|
||||
val cafeRequestDto = CafeTestUtils.createCafeRequestDto()
|
||||
val cafe = cafeRequestDto.let {
|
||||
Cafe.createCafe(
|
||||
name = it.name!!,
|
||||
address = it.address!!,
|
||||
phoneNumber = it.phoneNumber!!,
|
||||
description = it.description!!,
|
||||
cafeMenuRequestList = it.cafeMenuList
|
||||
)
|
||||
}
|
||||
|
||||
val savedId = cafeRepository.save(cafe).id
|
||||
|
||||
val findCafe = cafeRepository.findByIdOrNull(savedId)
|
||||
|
||||
val updatedName = "update cafe name"
|
||||
val updatedAddress = "update cafe address"
|
||||
val updatedPhoneNumber = "01011112222"
|
||||
val updatedDescription = "update description"
|
||||
|
||||
findCafe!!.updateInfo(
|
||||
name = updatedName,
|
||||
address = updatedAddress,
|
||||
phoneNumber = updatedPhoneNumber,
|
||||
description = updatedDescription
|
||||
)
|
||||
|
||||
val updatedCafe = cafeRepository.findByIdOrNull(savedId)
|
||||
|
||||
assertEquals(updatedName, updatedCafe!!.name)
|
||||
assertEquals(updatedAddress, updatedCafe.address)
|
||||
assertEquals(updatedPhoneNumber, updatedCafe.phoneNumber)
|
||||
assertEquals(updatedDescription, updatedCafe.description)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package io.beaniejoy.dongnecafe.domain.cafe.service
|
||||
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.entity.Cafe
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.error.CafeExistedException
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.error.CafeNotFoundException
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.repository.CafeRepository
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.utils.CafeTestUtils
|
||||
import org.junit.jupiter.api.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.mockito.InjectMocks
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.*
|
||||
import org.mockito.junit.jupiter.MockitoExtension
|
||||
import java.util.*
|
||||
import javax.persistence.GeneratedValue
|
||||
|
||||
@ExtendWith(MockitoExtension::class)
|
||||
@TestMethodOrder(MethodOrderer.DisplayName::class)
|
||||
internal class CafeServiceTest {
|
||||
@InjectMocks
|
||||
lateinit var mockCafeService: CafeService
|
||||
|
||||
@Mock
|
||||
lateinit var mockCafeRepository: CafeRepository
|
||||
|
||||
@Test
|
||||
@DisplayName("카페 신규 생성 테스트")
|
||||
fun create_cafe_test() {
|
||||
// given
|
||||
val cafeRequestDto = CafeTestUtils.createCafeRequestDto()
|
||||
val savedMockCafeId = 100L
|
||||
|
||||
`when`(mockCafeRepository.findByName(cafeRequestDto.name!!)).thenReturn(null)
|
||||
`when`(mockCafeRepository.save(any(Cafe::class.java))).thenAnswer {
|
||||
injectCafeId(it.getArgument(0), savedMockCafeId)
|
||||
}
|
||||
|
||||
// when
|
||||
val savedCafeId = mockCafeService.createCafe(
|
||||
name = cafeRequestDto.name!!,
|
||||
address = cafeRequestDto.address!!,
|
||||
phoneNumber = cafeRequestDto.phoneNumber!!,
|
||||
description = cafeRequestDto.description!!,
|
||||
cafeMenuRequestList = cafeRequestDto.cafeMenuList
|
||||
)
|
||||
|
||||
// then
|
||||
verify(mockCafeRepository).findByName(cafeRequestDto.name!!) // TODO eq 에러 발생 이유
|
||||
verify(mockCafeRepository).save(any(Cafe::class.java))
|
||||
|
||||
assertEquals(savedCafeId, savedMockCafeId)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("카페 신규 생성시 이미 존재하는 카페 예외 발생 테스트")
|
||||
fun fail_create_cafe_when_existed() {
|
||||
// given
|
||||
val cafeRequestDto = CafeTestUtils.createCafeRequestDto()
|
||||
val cafe = Cafe.createCafe(
|
||||
name = cafeRequestDto.name!!,
|
||||
address = cafeRequestDto.address!!,
|
||||
phoneNumber = cafeRequestDto.phoneNumber!!,
|
||||
description = cafeRequestDto.description!!,
|
||||
cafeMenuRequestList = cafeRequestDto.cafeMenuList
|
||||
)
|
||||
|
||||
`when`(mockCafeRepository.findByName(cafeRequestDto.name!!)).thenReturn(cafe)
|
||||
|
||||
// then
|
||||
assertThrows<CafeExistedException> {
|
||||
// when
|
||||
mockCafeService.createCafe(
|
||||
name = cafeRequestDto.name!!,
|
||||
address = cafeRequestDto.address!!,
|
||||
phoneNumber = cafeRequestDto.phoneNumber!!,
|
||||
description = cafeRequestDto.description!!,
|
||||
cafeMenuRequestList = cafeRequestDto.cafeMenuList
|
||||
)
|
||||
}
|
||||
|
||||
verify(mockCafeRepository).findByName(cafeRequestDto.name!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("카페 정보 변경 테스트")
|
||||
fun update_cafe_test() {
|
||||
// given
|
||||
val cafeRequestDto = CafeTestUtils.createCafeRequestDto()
|
||||
val cafe = Cafe.createCafe(
|
||||
name = cafeRequestDto.name!!,
|
||||
address = cafeRequestDto.address!!,
|
||||
phoneNumber = cafeRequestDto.phoneNumber!!,
|
||||
description = cafeRequestDto.description!!,
|
||||
cafeMenuRequestList = cafeRequestDto.cafeMenuList
|
||||
)
|
||||
val cafeId = 50L
|
||||
|
||||
// TODO findByIdOrNull은 kotlin test 라이브러리 필요한 듯
|
||||
`when`(mockCafeRepository.findById(cafeId)).thenReturn(Optional.of(cafe))
|
||||
|
||||
// then
|
||||
mockCafeService.updateCafe(
|
||||
id = cafeId,
|
||||
name = "",
|
||||
address = "",
|
||||
phoneNumber = "",
|
||||
description = "",
|
||||
)
|
||||
|
||||
verify(mockCafeRepository).findById(eq(cafeId))
|
||||
|
||||
// TODO update TEST 방법?
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("카페 정보 변경시 존재하지 않는 카페 예외 발생 테스트")
|
||||
fun fail_update_cafe_when_not_found() {
|
||||
// given
|
||||
val cafeId = 50L
|
||||
|
||||
`when`(mockCafeRepository.findById(cafeId)).thenReturn(Optional.empty())
|
||||
|
||||
assertThrows<CafeNotFoundException> {
|
||||
mockCafeService.updateCafe(
|
||||
id = cafeId,
|
||||
name = "",
|
||||
address = "",
|
||||
phoneNumber = "",
|
||||
description = "",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package io.beaniejoy.dongnecafe.domain.cafe.utils
|
||||
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.dto.request.CafeInfoRequestDto
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.dto.request.CafeMenuInfoRequestDto
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.dto.request.MenuOptionInfoRequestDto
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.dto.request.OptionDetailInfoRequestDto
|
||||
import io.beaniejoy.dongnecafe.domain.cafe.entity.Cafe
|
||||
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 org.junit.jupiter.api.Assertions.*
|
||||
import java.math.BigDecimal
|
||||
|
||||
class CafeTestUtils {
|
||||
companion object {
|
||||
fun assertCafeEquals(request: CafeInfoRequestDto, entity: Cafe) {
|
||||
assertEquals(request.name, entity.name)
|
||||
assertEquals(request.address, entity.address)
|
||||
assertEquals(request.phoneNumber, entity.phoneNumber)
|
||||
assertEquals(request.description, entity.description)
|
||||
|
||||
assertCafeMenuListEquals(request.cafeMenuList, entity.cafeMenuList)
|
||||
}
|
||||
|
||||
private fun assertCafeMenuListEquals(
|
||||
cafeMenuRequestList: List<CafeMenuInfoRequestDto>,
|
||||
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<MenuOptionInfoRequestDto>,
|
||||
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<OptionDetailInfoRequestDto>,
|
||||
optionDetailList: MutableList<OptionDetail>,
|
||||
) {
|
||||
for (index in optionDetailRequestList.indices) {
|
||||
assertEquals(optionDetailRequestList[index].name, optionDetailList[index].name)
|
||||
assertEquals(optionDetailRequestList[index].extraPrice, optionDetailList[index].extraPrice)
|
||||
}
|
||||
}
|
||||
|
||||
fun createCafeRequestDto(): CafeInfoRequestDto {
|
||||
val cafeName = "beanie_cafe"
|
||||
val cafeAddress = "beanie_cafe_address"
|
||||
val phoneNumber = "01012345678"
|
||||
val description = "beanie_cafe_description"
|
||||
|
||||
val sizeOptionDetailList = listOf(
|
||||
OptionDetailInfoRequestDto(name = "medium", extraPrice = BigDecimal.ZERO),
|
||||
OptionDetailInfoRequestDto(name = "large", extraPrice = BigDecimal.valueOf(200L)),
|
||||
OptionDetailInfoRequestDto(name = "venti", extraPrice = BigDecimal.valueOf(700L))
|
||||
)
|
||||
val sizeMenuOption = MenuOptionInfoRequestDto(
|
||||
title = "size",
|
||||
optionDetailList = sizeOptionDetailList
|
||||
)
|
||||
|
||||
val cafeMenuList = listOf(
|
||||
CafeMenuInfoRequestDto(
|
||||
name = "menu1",
|
||||
price = BigDecimal.valueOf(2_800L),
|
||||
menuOptionList = listOf(sizeMenuOption)
|
||||
),
|
||||
CafeMenuInfoRequestDto(
|
||||
name = "menu2",
|
||||
price = BigDecimal.valueOf(3_500L),
|
||||
menuOptionList = listOf(sizeMenuOption)
|
||||
),
|
||||
)
|
||||
|
||||
return CafeInfoRequestDto(
|
||||
name = cafeName,
|
||||
address = cafeAddress,
|
||||
phoneNumber = phoneNumber,
|
||||
description = description,
|
||||
cafeMenuList = cafeMenuList
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/test/resources/application.yml
Normal file
13
src/test/resources/application.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
spring:
|
||||
flyway:
|
||||
enabled: false
|
||||
jpa:
|
||||
properties:
|
||||
hibernate:
|
||||
format_sql: true
|
||||
show_sql: false
|
||||
|
||||
logging:
|
||||
level:
|
||||
org.hibernate.SQL: debug
|
||||
org.hibernate.type: trace
|
||||
Reference in New Issue
Block a user