Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[개선] 가게 생성 시 주소 정보 추가 (issue#79) #82

Merged
merged 13 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from 9 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
4 changes: 3 additions & 1 deletion .github/workflows/mealkitary-main-develop-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ jobs:
./mealkitary-infrastructure/adapter-paymentgateway-tosspayments/build/test-results/**/*.xml
./mealkitary-infrastructure/adapter-firebase-notification/build/test-results/**/*.xml
./mealkitary-infrastructure/business-registration-number-validator/adapter-simple-brn-validator/build/test-results/**/*.xml
./mealkitary-infrastructure/adapter-address-resolver/build/test-results/**/*.xml

- name: Jacoco Coverage 리포트 전송
uses: codecov/codecov-action@v3
Expand All @@ -67,7 +68,8 @@ jobs:
./mealkitary-infrastructure/adapter-persistence-spring-data-jpa/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/adapter-paymentgateway-tosspayments/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/adapter-firebase-notification/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/business-registration-number-validator/adapter-simple-brn-validator/build/reports/jacoco/test/jacocoTestReport.xml
./mealkitary-infrastructure/business-registration-number-validator/adapter-simple-brn-validator/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/adapter-address-resolver/build/reports/jacoco/test/jacocoTestReport.xml,
name: mealkitary-codecov
verbose: true

Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/mealkitary-test-coverage-automation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ jobs:
./mealkitary-infrastructure/adapter-paymentgateway-tosspayments/build/test-results/**/*.xml
./mealkitary-infrastructure/adapter-firebase-notification/build/test-results/**/*.xml
./mealkitary-infrastructure/business-registration-number-validator/adapter-simple-brn-validator/build/test-results/**/*.xml
./mealkitary-infrastructure/adapter-address-resolver/build/test-results/**/*.xml

- name: Jacoco Coverage 리포트 전송
uses: codecov/codecov-action@v3
Expand All @@ -55,6 +56,8 @@ jobs:
./mealkitary-infrastructure/adapter-persistence-spring-data-jpa/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/adapter-paymentgateway-tosspayments/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/adapter-firebase-notification/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/business-registration-number-validator/adapter-simple-brn-validator/build/reports/jacoco/test/jacocoTestReport.xml
./mealkitary-infrastructure/business-registration-number-validator/adapter-simple-brn-validator/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/adapter-address-resolver/build/reports/jacoco/test/jacocoTestReport.xml

name: mealkitary-codecov
verbose: true
2 changes: 2 additions & 0 deletions mealkitary-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ val snippetsDir by extra { file("build/generated-snippets") }
val asciidoctorExt: Configuration by configurations.creating

bootJar.enabled = true
bootJar.duplicatesStrategy = DuplicatesStrategy.EXCLUDE
jar.enabled = false

plugins {
Expand All @@ -21,6 +22,7 @@ dependencies {
implementation(project(":mealkitary-infrastructure:adapter-persistence-spring-data-jpa"))
implementation(project(":mealkitary-infrastructure:adapter-paymentgateway-tosspayments"))
implementation(project(":mealkitary-infrastructure:adapter-firebase-notification"))
implementation(project(":mealkitary-infrastructure:adapter-address-resolver"))
implementation(
project(
":mealkitary-infrastructure:business-registration-number-validator:adapter-open-api-brn-validator",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ data class RegisterShopWebRequest(
val title: String? = null,

@field:NotBlank(message = "사업자 번호는 필수입니다.")
val brn: String? = null
val brn: String? = null,

@field:NotBlank(message = "주소는 필수입니다.")
val address: String? = null
) {

fun mapToServiceRequest() = RegisterShopRequest(title!!, brn!!)
fun mapToServiceRequest() = RegisterShopRequest(title!!, brn!!, address!!)
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class RegisterShopControllerDocsTest : RestDocsSupport() {
fun `api docs test - registerShop`() {
every { registerShopUseCase.register(any()) } answers { 1L }

val registerShopWebRequest = RegisterShopWebRequest("집밥뚝딱 안양점", "123-23-12345")
val registerShopWebRequest = RegisterShopWebRequest("집밥뚝딱 안양점", "123-23-12345", "경기도 안양시 동안구 벌말로")

mvc.perform(
RestDocumentationRequestBuilders.post("/shops")
Expand All @@ -45,6 +45,7 @@ class RegisterShopControllerDocsTest : RestDocsSupport() {
requestFields(
fieldWithPath("title").type(JsonFieldType.STRING).description("등록 대상 가게 이름"),
fieldWithPath("brn").type(JsonFieldType.STRING).description("사업자 번호"),
fieldWithPath("address").type(JsonFieldType.STRING).description("가게 도로명 주소"),
le2sky marked this conversation as resolved.
Show resolved Hide resolved
),
responseHeaders(headerWithName("Location").description("생성된 가게 리소스 URI")),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class RegisterShopControllerTest : WebIntegrationTestSupport() {
fun `api integration test - registerShop`() {
every { registerShopUseCase.register(any()) } answers { 1L }

val registerShopWebRequest = RegisterShopWebRequest("집밥뚝딱 안양점", "123-23-12345")
val registerShopWebRequest = RegisterShopWebRequest("집밥뚝딱 안양점", "123-23-12345", "경기도 안양시 동안구 벌말로 40")

mvc.perform(
MockMvcRequestBuilders.post("/shops")
Expand All @@ -28,7 +28,7 @@ class RegisterShopControllerTest : WebIntegrationTestSupport() {

@Test
fun `api integration test - 가게 이름이 누락된 경우 400 에러를 발생한다`() {
val registerShopWebRequest = RegisterShopWebRequest(brn = "123-23-12345")
val registerShopWebRequest = RegisterShopWebRequest(brn = "123-23-12345", address = "경기도 안양시 동안구 벌말로 40")

mvc.perform(
MockMvcRequestBuilders.post("/shops")
Expand All @@ -44,7 +44,7 @@ class RegisterShopControllerTest : WebIntegrationTestSupport() {

@Test
fun `api integration test - 사업자 번호가 누락된 경우 400 에러를 발생한다`() {
val registerShopWebRequest = RegisterShopWebRequest(title = "집밥뚝딱 안양점")
val registerShopWebRequest = RegisterShopWebRequest(title = "집밥뚝딱 안양점", address = "경기도 안양시 동안구 벌말로 40")

mvc.perform(
MockMvcRequestBuilders.post("/shops")
Expand All @@ -58,6 +58,22 @@ class RegisterShopControllerTest : WebIntegrationTestSupport() {
.andExpect(jsonPath("$..errors[0].reason").value("사업자 번호는 필수입니다."))
}

@Test
fun `api integration test - 주소가 누락된 경우 400 에러를 발생한다`() {
val registerShopWebRequest = RegisterShopWebRequest(title = "집밥뚝딱 안양점", brn = "123-23-12345")

mvc.perform(
MockMvcRequestBuilders.post("/shops")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(registerShopWebRequest))
)
.andExpect(status().isBadRequest)
.andExpect(jsonPath("$.status").value("400"))
.andExpect(jsonPath("$.message").value("잘못된 입력값입니다."))
.andExpect(jsonPath("$..errors[0].field").value("address"))
.andExpect(jsonPath("$..errors[0].reason").value("주소는 필수입니다."))
}

@Test
fun `api integration test - JSON 형식이 아닌 경우 400 에러가 발생한다`() {
mvc.perform(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ package com.mealkitary.shop.application.port.input

data class RegisterShopRequest(
val title: String,
val brn: String
val brn: String,
val address: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@ package com.mealkitary.shop.application.service
import com.mealkitary.shop.application.port.input.RegisterShopRequest
import com.mealkitary.shop.application.port.input.RegisterShopUseCase
import com.mealkitary.shop.application.port.output.SaveShopPort
import com.mealkitary.shop.domain.shop.factory.ShopBusinessNumberValidator
import com.mealkitary.shop.domain.shop.factory.ShopFactory
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
@Transactional(readOnly = true)
@Transactional
class RegisterShopService(
private val saveShopPort: SaveShopPort,
shopBusinessNumberValidator: ShopBusinessNumberValidator
private val shopFactory: ShopFactory
) : RegisterShopUseCase {

private val shopFactory = ShopFactory(shopBusinessNumberValidator)

@Transactional
override fun register(registerShopRequest: RegisterShopRequest): Long {
val shop = shopFactory.createOne(registerShopRequest.title, registerShopRequest.brn)
val shop = shopFactory.createOne(
registerShopRequest.title,
registerShopRequest.brn,
registerShopRequest.address
)

return saveShopPort.saveOne(shop)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import com.mealkitary.shop.domain.shop.Shop
import com.mealkitary.shop.domain.shop.ShopBusinessNumber
import com.mealkitary.shop.domain.shop.ShopStatus
import com.mealkitary.shop.domain.shop.ShopTitle
import com.mealkitary.shop.domain.shop.address.Address
import com.mealkitary.shop.domain.shop.address.Coordinates
import com.mealkitary.shop.domain.shop.address.ShopAddress
import io.kotest.core.spec.style.AnnotationSpec
import io.kotest.matchers.shouldBe
import io.mockk.every
Expand All @@ -24,6 +27,19 @@ class GetShopServiceTest : AnnotationSpec() {
ShopTitle.from("집밥뚝딱"),
ShopStatus.VALID,
ShopBusinessNumber.from("123-45-67890"),
ShopAddress.of(
"1234567890",
Coordinates.of(
126.99599512792346,
35.976749396987046
),
Address.of(
"region1DepthName",
"region2DepthName",
"region3DepthName",
"roadName"
)
),
mutableListOf(),
mutableListOf()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@ package com.mealkitary.shop.application.service

import com.mealkitary.shop.application.port.input.RegisterShopRequest
import com.mealkitary.shop.application.port.output.SaveShopPort
import com.mealkitary.shop.domain.product.Product
import com.mealkitary.shop.domain.shop.Shop
import com.mealkitary.shop.domain.shop.ShopBusinessNumber
import com.mealkitary.shop.domain.shop.ShopStatus
import com.mealkitary.shop.domain.shop.ShopTitle
import com.mealkitary.shop.domain.shop.address.Address
import com.mealkitary.shop.domain.shop.address.Coordinates
import com.mealkitary.shop.domain.shop.address.ShopAddress
import com.mealkitary.shop.domain.shop.factory.AddressResolver
import com.mealkitary.shop.domain.shop.factory.ShopBusinessNumberValidator
import com.mealkitary.shop.domain.shop.factory.ShopFactory
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.AnnotationSpec
import io.kotest.matchers.collections.shouldBeEmpty
Expand All @@ -12,35 +21,60 @@ import io.kotest.matchers.throwable.shouldHaveMessage
import io.mockk.every
import io.mockk.mockk
import io.mockk.slot
import java.time.LocalTime

class RegisterShopServiceTest : AnnotationSpec() {

private val saveShopPort = mockk<SaveShopPort>()
private val shopFactory = mockk<ShopFactory>()
private val shopBusinessNumberValidator = mockk<ShopBusinessNumberValidator>()
private val registerShopService = RegisterShopService(saveShopPort, shopBusinessNumberValidator)
private val addressResolver = mockk<AddressResolver>()
private val registerShopService = RegisterShopService(saveShopPort, shopFactory)

@Test
fun `service unit test - 신규 가게를 등록한다`() {
val shopSlot = slot<Shop>()
val request = RegisterShopRequest("집밥뚝딱 안양점", "123-23-12345")
val request = RegisterShopRequest("집밥뚝딱 안양점", "123-23-12345", "경기도 안양시 동안구 벌말로 40")
val expectedShopAddress =
ShopAddress.of("1234567890", Coordinates.of(0.0, 0.0), Address.of("경기도", "안양시 동안구", "벌말로", "40"))

val mockedShop = Shop(
ShopTitle.from(request.title),
ShopStatus.VALID,
ShopBusinessNumber.from(request.brn),
expectedShopAddress,
emptyList<LocalTime>().toMutableList(),
emptyList<Product>().toMutableList()
)

every {
shopFactory.createOne(request.title, request.brn, request.address)
} returns mockedShop
every { saveShopPort.saveOne(capture(shopSlot)) } answers { 1L }
every { shopBusinessNumberValidator.validate(any()) } answers {}

val result = registerShopService.register(request)

val capturedShop = shopSlot.captured
result shouldBe 1L
capturedShop.businessNumber.value shouldBe "123-23-12345"
capturedShop.title.value shouldBe "집밥뚝딱 안양점"
capturedShop.address shouldBe expectedShopAddress
capturedShop.products.shouldBeEmpty()
capturedShop.reservableTimes.shouldBeEmpty()
}

@Test
fun `service unit test - 가게 이름 형식에 맞지 않으면 예외를 발생한다`() {
val request = RegisterShopRequest("invalid!#@", "123-23-12345")
val request = RegisterShopRequest("invalid!#@", "123-23-12345", "경기도 안양시 동안구 벌말로 40")
val expectedShopAddress =
ShopAddress.of("1234567890", Coordinates.of(0.0, 0.0), Address.of("경기도", "안양시 동안구", "벌말로", "40"))

every {
shopFactory.createOne(any(), any(), any())
} throws IllegalArgumentException("올바른 가게 이름 형식이 아닙니다.(한글, 영문, 공백, 숫자만 포함 가능)")
every { saveShopPort.saveOne(any()) } answers { 1L }
every { shopBusinessNumberValidator.validate(any()) } answers {}
every { addressResolver.resolveAddress("경기도 안양시 동안구 벌말로 40") } returns expectedShopAddress

shouldThrow<IllegalArgumentException> {
registerShopService.register(request)
Expand All @@ -49,7 +83,11 @@ class RegisterShopServiceTest : AnnotationSpec() {

@Test
fun `service unit test - 사업자 번호 형식에 맞지 않으면 예외를 발생한다`() {
val request = RegisterShopRequest("집밥뚝딱 안양점", "invalid-brn")
val request = RegisterShopRequest("집밥뚝딱 안양점", "invalid-brn", "경기도 안양시 동안구 벌말로 40")

every {
shopFactory.createOne(any(), any(), any())
} throws IllegalArgumentException("올바른 사업자번호 형식이 아닙니다.")
every { saveShopPort.saveOne(any()) } answers { 1L }
every { shopBusinessNumberValidator.validate(any()) } answers {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import com.mealkitary.shop.domain.shop.Shop
import com.mealkitary.shop.domain.shop.ShopBusinessNumber
import com.mealkitary.shop.domain.shop.ShopStatus
import com.mealkitary.shop.domain.shop.ShopTitle
import com.mealkitary.shop.domain.shop.address.Address
import com.mealkitary.shop.domain.shop.address.Coordinates
import com.mealkitary.shop.domain.shop.address.ShopAddress
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.AnnotationSpec
import io.kotest.matchers.shouldBe
Expand All @@ -25,6 +28,19 @@ class UpdateShopStatusServiceTest : AnnotationSpec() {
ShopTitle.from("제목"),
ShopStatus.VALID,
ShopBusinessNumber.from("123-12-12345"),
ShopAddress.of(
"1234567890",
Coordinates.of(
126.99599512792346,
35.976749396987046
),
Address.of(
"region1DepthName",
"region2DepthName",
"region3DepthName",
"roadName"
)
),
mutableListOf(),
mutableListOf()
)
Expand All @@ -44,6 +60,19 @@ class UpdateShopStatusServiceTest : AnnotationSpec() {
ShopTitle.from("제목"),
ShopStatus.INVALID,
ShopBusinessNumber.from("123-12-12345"),
ShopAddress.of(
"1234567890",
Coordinates.of(
126.99599512792346,
35.976749396987046
),
Address.of(
"region1DepthName",
"region2DepthName",
"region3DepthName",
"roadName"
)
),
mutableListOf(),
mutableListOf()
)
Expand All @@ -63,6 +92,19 @@ class UpdateShopStatusServiceTest : AnnotationSpec() {
ShopTitle.from("제목"),
ShopStatus.VALID,
ShopBusinessNumber.from("123-12-12345"),
ShopAddress.of(
"1234567890",
Coordinates.of(
126.99599512792346,
35.976749396987046
),
Address.of(
"region1DepthName",
"region2DepthName",
"region3DepthName",
"roadName"
)
),
mutableListOf(),
mutableListOf()
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.mealkitary.shop.domain.shop

import com.mealkitary.shop.domain.product.Product
import com.mealkitary.shop.domain.shop.address.ShopAddress
import java.time.LocalDateTime
import java.time.LocalTime
import javax.persistence.CascadeType
Expand All @@ -23,6 +24,7 @@ class Shop(
title: ShopTitle,
status: ShopStatus,
businessNumber: ShopBusinessNumber,
address: ShopAddress,
reservableTimes: MutableList<LocalTime>,
products: MutableList<Product>
) {
Expand Down Expand Up @@ -58,6 +60,8 @@ class Shop(

val businessNumber: ShopBusinessNumber = businessNumber

val address: ShopAddress = address

fun checkReservableShop() {
if (status.isInvalidStatus()) {
throw IllegalStateException("유효하지 않은 가게입니다.")
Expand Down
Loading