[만들면서 배우는 클린 아키텍처] 테스트 예제 코드 보충 (#10)
* 만들면서 배우는 클린 아키텍처 initial commit * refactor : 프로젝트 진입점 클래스 이름 변경 * docs : README.md 헥사고날 아키텍처 항목 추가 * docs(README.md) : 내용 정리 추가 * feat(user.domain) : 도메인 모델 User 추가 * feat(user.domain) : User 의 nickname 프로퍼티 값 객체로 포장 * refactor(User) : 닉네임 변경 함수 이름 수정 * test(user.domain) : 회원 닉네임 변경 테스트 추가 * chore : DB 설정 추가 * feat(user.adapter) : User Entity 구현 * feat : User 닉네임 변경 기능 추가 * refactor(user) : domain 패키지 내부 패키지 구성 추가 및 Entity, Model 이관 * refactor : 사용하지 않는 파일 삭제 * refactor : User 닉네임 변경 기능 컴포넌트 이름 변경 * refactor : User 닉네임 변경 기능 in port 이름 변경 * feat : User Upsert Port 및 Adapter 구현, Service 로직에 추가 * chore : Hexagonal Architecture Process 이미지 추가 * docs(README.md) : 요구사항, 구현 항목 추가 * refactor : 패키지 구성 변경 * feat(user.adapter) : UserMapper 추가 및 적용 * docs(README.md) : 참고자료 및 구현 항목 내용 추가 * refactor : ChangeNicknameRequest, ChangeNicknameResponse 패키지 변경 * refactor : adapter 계층만 application 계층에 의존하도록 통신 객체 추가 및 적용 * refactor : UserEntity @Table 이름 적용 * docs(README.md) : 구현 항목 내용 추가 * refactor : Nickname 입력 유효성 검사 ChangeNicknameRequest 에서 수행하도록 변경 * refactor(user.pojo) : 불필요한 테스트 삭제 * refactor(UserTest) : 오탈자 수정 * build : Kotlin 테스트 라이브러리 추가 * test(user.application) : 닉네임 변경 테스트 추가 * test(user.adapter) : 회원 조회 테스트 추가 * refactor : 불필요한 파일 삭제 * test(user.adapter) : 회원 상태 저장 또는 수정 테스트 추가 * test(user.adapter) : User POJO <-> User Entity 매핑 테스트 추가 * test(user.adapter) : 닉네임 변경 Web Adapter 테스트 추가 * refactor : 불필요한 테스트 파일 삭제 * refactor(user) : 닉네임 변경 테스트 케이스 출력 이름 변경
This commit is contained in:
@@ -25,11 +25,15 @@ dependencies {
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
|
||||
runtimeOnly("com.h2database:h2")
|
||||
runtimeOnly("mysql:mysql-connector-java")
|
||||
runtimeOnly("org.mariadb.jdbc:mariadb-java-client")
|
||||
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||
// testImplementation("org.springframework.security:spring-security-test")
|
||||
testImplementation("io.mockk:mockk:1.12.3")
|
||||
testImplementation("com.ninja-squad:springmockk:3.1.1")
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile> {
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.banjjoknim.playground
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.runApplication
|
||||
|
||||
@SpringBootApplication
|
||||
class LearnWithMakingCleanArchitectureApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
runApplication<LearnWithMakingCleanArchitectureApplication>(*args)
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.banjjoknim.cleanarchitecture.user.adapter.`in`.web
|
||||
|
||||
import com.banjjoknim.cleanarchitecture.user.application.port.`in`.ChangeNicknameResponseData
|
||||
import com.banjjoknim.cleanarchitecture.user.application.port.`in`.ChangeNicknameUseCase
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.ninjasquad.springmockk.MockkBean
|
||||
import io.mockk.every
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.post
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultHandlers
|
||||
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders
|
||||
import org.springframework.web.context.WebApplicationContext
|
||||
import org.springframework.web.filter.CharacterEncodingFilter
|
||||
|
||||
@WebMvcTest(ChangeNicknameWebAdapter::class)
|
||||
class ChangeNicknameWebAdapterTest {
|
||||
|
||||
@Autowired
|
||||
private lateinit var mockmvc: MockMvc
|
||||
|
||||
@Autowired
|
||||
private lateinit var objectMapper: ObjectMapper
|
||||
|
||||
@MockkBean
|
||||
private lateinit var changeNicknameUseCase: ChangeNicknameUseCase
|
||||
|
||||
@BeforeEach
|
||||
fun setUp(webApplicationContext: WebApplicationContext) {
|
||||
mockmvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
|
||||
.addFilter<DefaultMockMvcBuilder>(CharacterEncodingFilter("UTF-8"))
|
||||
.alwaysDo<DefaultMockMvcBuilder>(MockMvcResultHandlers.print())
|
||||
.build()
|
||||
}
|
||||
|
||||
@DisplayName("닉네임 변경 테스트 케이스")
|
||||
@Nested
|
||||
inner class ChangeNicknameTestCases {
|
||||
@Test
|
||||
fun `닉네임을 변경한다`() {
|
||||
every { changeNicknameUseCase.changeNickname(any()) } returns ChangeNicknameResponseData(1L)
|
||||
val request = ChangeNicknameRequest(1L, "banjjoknim")
|
||||
|
||||
mockmvc.post("/users") {
|
||||
contentType = MediaType.APPLICATION_JSON
|
||||
content = objectMapper.writeValueAsString(request)
|
||||
}.andExpect {
|
||||
content { json("""{"userId":1}""") }
|
||||
status { isOk() }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `잘못된 닉네임 변경 요청에 BadRequest 응답을 반환한다`() {
|
||||
val request = ChangeNicknameRequest(1L, "banjjoknim!!")
|
||||
|
||||
mockmvc.post("/users") {
|
||||
contentType = MediaType.APPLICATION_JSON
|
||||
content = objectMapper.writeValueAsString(request)
|
||||
}.andExpect {
|
||||
status { isBadRequest() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.banjjoknim.cleanarchitecture.user.adapter.out.persistence
|
||||
|
||||
import com.banjjoknim.cleanarchitecture.user.pojo.Nickname
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
|
||||
import org.springframework.context.annotation.Import
|
||||
import org.springframework.test.context.jdbc.Sql
|
||||
|
||||
@DataJpaTest
|
||||
@Import(value = [UserMapper::class, LoadUserPersistenceAdapter::class])
|
||||
class LoadUserPersistenceAdapterTest {
|
||||
|
||||
@Autowired
|
||||
private lateinit var loadUserPersistenceAdapter: LoadUserPersistenceAdapter
|
||||
|
||||
@DisplayName("회원 조회 테스트 케이스")
|
||||
@Nested
|
||||
inner class LoadUserTestCases {
|
||||
@Sql(statements = ["INSERT INTO USER VALUES (1, 'old')"])
|
||||
@Test
|
||||
fun `회원이 존재하지 않을 경우 예외가 발생한다`() {
|
||||
assertThrows<NoSuchElementException>("존재하지 않는 회원입니다. userId: 100") {
|
||||
loadUserPersistenceAdapter.loadUser(
|
||||
100L
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Sql(statements = ["INSERT INTO USER VALUES (1, 'old')"])
|
||||
@Test
|
||||
fun `회원이 존재할 경우 회원을 조회할 수 있다`() {
|
||||
val user = loadUserPersistenceAdapter.loadUser(1L)
|
||||
|
||||
Assertions.assertThat(user.id).isEqualTo(1)
|
||||
Assertions.assertThat(user.nickname).isEqualTo(Nickname("old"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.banjjoknim.cleanarchitecture.user.adapter.out.persistence
|
||||
|
||||
import com.banjjoknim.cleanarchitecture.user.pojo.Nickname
|
||||
import com.banjjoknim.cleanarchitecture.user.pojo.User
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Nested
|
||||
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.Import
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.test.context.jdbc.Sql
|
||||
|
||||
@DataJpaTest
|
||||
@Import(value = [UserMapper::class, UpsertUserPersistenceAdapter::class])
|
||||
class UpsertUserPersistenceAdapterTest {
|
||||
|
||||
@Autowired
|
||||
private lateinit var upsertUserPersistenceAdapter: UpsertUserPersistenceAdapter
|
||||
|
||||
@Autowired
|
||||
private lateinit var userEntityRepository: UserEntityRepository
|
||||
|
||||
@DisplayName("회원 상태 저장 및 수정 테스트 케이스")
|
||||
@Nested
|
||||
inner class UpsertUserTestCases {
|
||||
@Sql(statements = ["INSERT INTO USER VALUES (1, 'old')"])
|
||||
@Test
|
||||
fun `회원 상태를 저장하거나 수정한다`() {
|
||||
val updatedUser = User(1L, Nickname("new"))
|
||||
|
||||
upsertUserPersistenceAdapter.upsertUser(updatedUser)
|
||||
|
||||
val userEntity = userEntityRepository.findByIdOrNull(1L)
|
||||
assertThat(userEntity?.nickname).isEqualTo(NicknameColumn("new"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.banjjoknim.cleanarchitecture.user.adapter.out.persistence
|
||||
|
||||
import com.banjjoknim.cleanarchitecture.user.pojo.Nickname
|
||||
import com.banjjoknim.cleanarchitecture.user.pojo.User
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
|
||||
@SpringBootTest(classes = [UserMapper::class])
|
||||
class UserMapperTest {
|
||||
|
||||
@Autowired
|
||||
private lateinit var userMapper: UserMapper
|
||||
|
||||
@DisplayName("User POJO <-> User Entity 매핑 테스트 케이스")
|
||||
@Nested
|
||||
inner class UserMapperTestCases {
|
||||
@Test
|
||||
fun `User POJO 를 User Entity 로 변환한다`() {
|
||||
val user = User(1L, Nickname("banjjoknim"))
|
||||
|
||||
val userEntity = userMapper.mapToDomainEntity(user)
|
||||
|
||||
assertThat(userEntity.id).isEqualTo(1)
|
||||
assertThat(userEntity.nickname).isEqualTo(NicknameColumn("banjjoknim"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `User Entity 를 User POJO 로 변환한다`() {
|
||||
val userEntity = UserEntity(1L, NicknameColumn("banjjoknim"))
|
||||
|
||||
val user = userMapper.mapToDomainModel(userEntity)
|
||||
|
||||
assertThat(user.id).isEqualTo(1)
|
||||
assertThat(user.nickname).isEqualTo(Nickname("banjjoknim"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.banjjoknim.cleanarchitecture.user.application.service
|
||||
|
||||
import com.banjjoknim.cleanarchitecture.user.application.port.`in`.ChangeNicknameRequestData
|
||||
import com.banjjoknim.cleanarchitecture.user.application.port.out.LoadUserPersistencePort
|
||||
import com.banjjoknim.cleanarchitecture.user.application.port.out.UpsertUserPersistencePort
|
||||
import com.banjjoknim.cleanarchitecture.user.pojo.Nickname
|
||||
import com.banjjoknim.cleanarchitecture.user.pojo.User
|
||||
import io.mockk.Runs
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class ChangeNicknameServiceTest {
|
||||
|
||||
private val loadUserPersistencePort = mockk<LoadUserPersistencePort>()
|
||||
private val upsertUserPersistencePort = mockk<UpsertUserPersistencePort>()
|
||||
private val changeNicknameService = ChangeNicknameService(loadUserPersistencePort, upsertUserPersistencePort)
|
||||
|
||||
@DisplayName("닉네임 변경 테스트 케이스")
|
||||
@Nested
|
||||
inner class ChangeNicknameTestCases {
|
||||
|
||||
private lateinit var testUser: User
|
||||
private val testChangeNicknameRequestData = ChangeNicknameRequestData(1L, "new")
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
testUser = User(1L, Nickname("old"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `닉네임을 변경한다`() {
|
||||
every { loadUserPersistencePort.loadUser(any()) } returns testUser
|
||||
every { upsertUserPersistencePort.upsertUser(any()) } just Runs
|
||||
|
||||
changeNicknameService.changeNickname(testChangeNicknameRequestData)
|
||||
|
||||
assertThat(testUser.nickname).isEqualTo(Nickname("new"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,8 @@ import org.junit.jupiter.api.Test
|
||||
|
||||
class UserTest {
|
||||
|
||||
@DisplayName("회원 이름 변경 테스트 케이스")
|
||||
|
||||
@DisplayName("회원 닉네임 변경 테스트 케이스")
|
||||
@Nested
|
||||
inner class ChangeNicknameTestCases {
|
||||
@Test
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.banjjoknim.playground
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
|
||||
@SpringBootTest
|
||||
class LearnWithMakingCleanArchitectureApplicationTests {
|
||||
|
||||
@Test
|
||||
fun contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user