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

feat: 북마크 API 구현 #109

Merged
merged 7 commits into from
May 20, 2024
Merged
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
7 changes: 7 additions & 0 deletions Api-Module/src/docs/asciidoc/BookMark.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[[Bookmark-API]]
== Bookmark-API

[[CREATE-BOOKMARK]]
=== 북마크 생성 API

operation::BookmarkControllerTest/createBookmark/[snippets='http-request,path-parameters,request-headers,http-response']
1 change: 1 addition & 0 deletions Api-Module/src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ include::StrongPoint.adoc[]
include::Tag.adoc[]
include::JobDescription.adoc[]
include::Experience.adoc[]
include::BookMark.adoc[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.bamyanggang.apimodule.domain.bookmark.application

import com.bamyanggang.domainmodule.domain.bookmark.service.BookmarkAppender
import com.bamyanggang.domainmodule.domain.bookmark.service.BookmarkModifier
import com.bamyanggang.domainmodule.domain.bookmark.service.BookmarkReader
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.util.*

@Service
class BookmarkService(
private val bookmarkReader: BookmarkReader,
private val bookmarkModifier: BookmarkModifier,
private val bookmarkAppender: BookmarkAppender
) {

@Transactional
fun bookmark(jobDescriptionId: UUID, experienceId: UUID) {
bookmarkReader.readBookmark(jobDescriptionId, experienceId)?.let {
bookmarkModifier.modifyBookmarkStatus(it)
} ?: bookmarkAppender.appendBookmark(jobDescriptionId, experienceId)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.bamyanggang.apimodule.domain.bookmark.presentation

object BookmarkApi {
const val BASE_URL = "/api/bookmark"
const val BOOKMARK = "$BASE_URL/{jobDescriptionId}/{experienceId}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.bamyanggang.apimodule.domain.bookmark.presentation

import com.bamyanggang.apimodule.domain.bookmark.application.BookmarkService
import org.springframework.web.bind.annotation.PatchMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RestController
import java.util.UUID

@RestController
class BookmarkController(
private val bookmarkService: BookmarkService
) {

@PatchMapping(BookmarkApi.BOOKMARK)
fun bookmark(
@PathVariable("jobDescriptionId") jobDescriptionId: UUID,
@PathVariable("experienceId") experienceId: UUID
) {
bookmarkService.bookmark(jobDescriptionId, experienceId)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.bamyanggang.apimodule.domain.bookmark.application

import com.bamyanggang.domainmodule.domain.bookmark.aggregate.Bookmark
import com.bamyanggang.domainmodule.domain.bookmark.service.BookmarkAppender
import com.bamyanggang.domainmodule.domain.bookmark.service.BookmarkModifier
import com.bamyanggang.domainmodule.domain.bookmark.service.BookmarkReader
import io.kotest.core.spec.style.BehaviorSpec
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import java.util.*

class BookmarkServiceTest: BehaviorSpec({
val mockBookmarkReader = mockk<BookmarkReader>(relaxed = true)
val mockBookmarkModifier = mockk<BookmarkModifier>(relaxed = true)
val mockBookmarkAppender = mockk<BookmarkAppender>(relaxed = true)
val service = BookmarkService(mockBookmarkReader, mockBookmarkModifier, mockBookmarkAppender)

given("BookmarkService.bookmark") {
val jobDescriptionId = UUID.randomUUID()
val experienceId = UUID.randomUUID()

`when`("readBookmark가 null을 반환하면") {
every { mockBookmarkReader.readBookmark(jobDescriptionId, experienceId) } returns null
service.bookmark(jobDescriptionId, experienceId)
then("appendBookmark가 호출된다.") {
verify {
mockBookmarkAppender.appendBookmark(jobDescriptionId, experienceId)
}
}
}

`when`("readBookmark가 null이 아닌 값을 반환하면") {
val bookmark = mockk<Bookmark>()
every { mockBookmarkReader.readBookmark(jobDescriptionId, experienceId) } returns bookmark
service.bookmark(jobDescriptionId, experienceId)
then("modifyBookmarkStatus가 호출된다.") {
verify {
mockBookmarkModifier.modifyBookmarkStatus(bookmark)
}
}
}
}

})
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.bamyanggang.apimodule.domain.bookmark.presentation

import com.bamyanggang.apimodule.BaseRestDocsTest
import com.bamyanggang.apimodule.domain.bookmark.application.BookmarkService
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.http.MediaType
import org.springframework.restdocs.headers.HeaderDocumentation.headerWithName
import org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders
import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders
import org.springframework.restdocs.request.RequestDocumentation.parameterWithName
import org.springframework.restdocs.request.RequestDocumentation.pathParameters
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import java.util.*

@WebMvcTest(BookmarkController::class)
class BookmarkControllerTest: BaseRestDocsTest() {

@MockBean
private lateinit var bookmarkService: BookmarkService

@Test
@DisplayName("북마크 추가")
fun createBookmark() {
// given
val jobDescriptionId = UUID.randomUUID()
val experienceId = UUID.randomUUID()

val request = RestDocumentationRequestBuilders.patch(BookmarkApi.BOOKMARK, jobDescriptionId, experienceId)
.header("Authorization", "Bearer Access Token")
.contentType(MediaType.APPLICATION_JSON_VALUE)

//when
val result = mockMvc.perform(request)

// then
result.andExpect(status().isOk)
.andDo(
resultHandler.document(
requestHeaders(
headerWithName("Authorization").description("엑세스 토큰")
),
pathParameters(
parameterWithName("jobDescriptionId").description("jd 공고 ID"),
parameterWithName("experienceId").description("경험 ID")
)
)
)
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.bamyanggang.domainmodule.domain.bookmark.aggregate

import com.bamyanggang.domainmodule.common.entity.AggregateRoot
import com.bamyanggang.domainmodule.domain.bookmark.enums.BookmarkStatus
import java.util.UUID

data class Bookmark(
override val id: UUID = UUID.randomUUID(),
val jobDescriptionId: UUID,
val experienceId:UUID,
val bookmarkStatus: BookmarkStatus
): AggregateRoot {

fun changeBookmarkStatus(): Bookmark {
return when (bookmarkStatus) {
BookmarkStatus.ON -> copy(bookmarkStatus = BookmarkStatus.OFF)
BookmarkStatus.OFF -> copy(bookmarkStatus = BookmarkStatus.ON)
}
}

companion object {
fun create(
jobDescriptionId: UUID,
experienceId: UUID
): Bookmark {
return Bookmark(
jobDescriptionId = jobDescriptionId,
experienceId = experienceId,
bookmarkStatus = BookmarkStatus.ON
)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.bamyanggang.domainmodule.domain.bookmark.enums

enum class BookmarkStatus {
ON,
OFF
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.bamyanggang.domainmodule.domain.bookmark.repository

import com.bamyanggang.domainmodule.domain.bookmark.aggregate.Bookmark
import java.util.*

interface BookmarkRepository {

fun findByIds(jobDescriptionId : UUID, experienceId : UUID) : Bookmark?

fun save(bookmark: Bookmark)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.bamyanggang.domainmodule.domain.bookmark.service

import com.bamyanggang.domainmodule.domain.bookmark.aggregate.Bookmark
import com.bamyanggang.domainmodule.domain.bookmark.repository.BookmarkRepository
import org.springframework.stereotype.Service
import java.util.*

@Service
class BookmarkAppender(
private val bookmarkRepository: BookmarkRepository
) {
fun appendBookmark(jobDescriptionId: UUID, experienceId: UUID) {
Bookmark.create(jobDescriptionId, experienceId).also { bookmarkRepository.save(it) }
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.bamyanggang.domainmodule.domain.bookmark.service

import com.bamyanggang.domainmodule.domain.bookmark.aggregate.Bookmark
import com.bamyanggang.domainmodule.domain.bookmark.repository.BookmarkRepository
import org.springframework.stereotype.Service

@Service
class BookmarkModifier(
private val bookmarkRepository: BookmarkRepository
) {
fun modifyBookmarkStatus(bookmark: Bookmark) {
bookmark.changeBookmarkStatus().also { bookmarkRepository.save(it) }
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.bamyanggang.domainmodule.domain.bookmark.service

import com.bamyanggang.domainmodule.domain.bookmark.aggregate.Bookmark
import com.bamyanggang.domainmodule.domain.bookmark.repository.BookmarkRepository
import org.springframework.stereotype.Service
import java.util.*

@Service
class BookmarkReader(
private val bookmarkRepository: BookmarkRepository
) {

fun readBookmark(jobDescriptionId: UUID, experienceId: UUID) : Bookmark? {
return bookmarkRepository.findByIds(jobDescriptionId, experienceId)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.bamyanggang.domainmodule.domain.bookmark.aggregate

import com.bamyanggang.commonmodule.fixture.generateFixture
import com.bamyanggang.domainmodule.domain.bookmark.enums.BookmarkStatus
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import java.util.*

class BookmarkTest : FunSpec({
test("북마크 생성") {
// arrange
val jobDescriptionId = UUID.randomUUID()
val experienceId = UUID.randomUUID()

// act
val bookmark: Bookmark = generateFixture {
it.set("jobDescriptionId", jobDescriptionId)
it.set("experienceId", experienceId)
}

// assert
bookmark.jobDescriptionId shouldBe jobDescriptionId
bookmark.experienceId shouldBe experienceId
}

test("북마크 상태 변경") {
// arrange
val jobDescriptionId = UUID.randomUUID()
val experienceId = UUID.randomUUID()
val bookmark: Bookmark = generateFixture {
it.set("jobDescriptionId", jobDescriptionId)
it.set("experienceId", experienceId)
it.set("bookmarkStatus", BookmarkStatus.ON)
}

// act
val changedBookmark = bookmark.changeBookmarkStatus()

// assert
changedBookmark.bookmarkStatus shouldBe BookmarkStatus.OFF
}

})
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.bamyanggang.domainmodule.domain.bookmark.service

import com.bamyanggang.domainmodule.domain.bookmark.repository.BookmarkRepository
import io.kotest.core.spec.style.BehaviorSpec
import io.mockk.mockk
import io.mockk.verify
import java.util.*

class BookmarkAppenderTest: BehaviorSpec({
val mockBookmarkRepository = mockk<BookmarkRepository>(relaxed = true)
val bookmarkAppender = BookmarkAppender(mockBookmarkRepository)

given("BookmarkAppender의 appendBookmark 메소드를 테스트한다") {
val jobDescriptionId = UUID.randomUUID()
val experienceId = UUID.randomUUID()
`when`("북마크를 추가하면") {
bookmarkAppender.appendBookmark(jobDescriptionId, experienceId)
then("북마크가 저장된다") {
verify(exactly = 1) {
mockBookmarkRepository.save(any())
}
}
}
}

})
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.bamyanggang.domainmodule.domain.bookmark.service

import com.bamyanggang.domainmodule.domain.bookmark.aggregate.Bookmark
import com.bamyanggang.domainmodule.domain.bookmark.repository.BookmarkRepository
import io.kotest.core.spec.style.BehaviorSpec
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify

class BookmarkModifierTest: BehaviorSpec({
val mockBookmarkRepository = mockk<BookmarkRepository>(relaxed = true)
val bookmarkModifier = BookmarkModifier(mockBookmarkRepository)

given("BookmarkModifier의 modifyBookmarkStatus 메소드를 테스트한다") {
val bookmark = mockk<Bookmark>()
every { bookmark.changeBookmarkStatus() } returns bookmark

`when`("북마크 상태를 변경하면") {
bookmarkModifier.modifyBookmarkStatus(bookmark)
then("북마크가 저장된다") {
verify(exactly = 1) {
mockBookmarkRepository.save(bookmark)
}
}
}
}

})
Loading
Loading