41 Commits

Author SHA1 Message Date
banjjoknim
ca95300a55 refactor : 부적합한 테스트 삭제 2022-04-26 21:00:23 +09:00
Colt
a68e3795e0 Merge branch 'main' into learn-with-making-clean-architecture 2022-04-26 20:57:09 +09:00
banjjoknim
8b44269f2a refactor(user) : 닉네임 변경 테스트 케이스 출력 이름 변경 2022-04-25 02:41:10 +09:00
banjjoknim
6ae3ded333 refactor : 불필요한 테스트 파일 삭제 2022-04-25 02:40:20 +09:00
banjjoknim
f23dd4ee6f test(user.adapter) : 닉네임 변경 Web Adapter 테스트 추가 2022-04-25 02:33:33 +09:00
banjjoknim
8239f77094 test(user.adapter) : User POJO <-> User Entity 매핑 테스트 추가 2022-04-25 01:20:06 +09:00
banjjoknim
0b79fdeaca test(user.adapter) : 회원 상태 저장 또는 수정 테스트 추가 2022-04-25 01:02:50 +09:00
banjjoknim
c023829329 refactor : 불필요한 파일 삭제 2022-04-25 00:24:44 +09:00
banjjoknim
d9cd347140 Merge remote-tracking branch 'origin/learn-with-making-clean-architecture' into learn-with-making-clean-architecture 2022-04-24 19:33:46 +09:00
banjjoknim
c67e54eea9 test(user.adapter) : 회원 조회 테스트 추가 2022-04-24 19:29:01 +09:00
banjjoknim
d9d951604a test(user.application) : 닉네임 변경 테스트 추가 2022-04-24 19:02:21 +09:00
banjjoknim
055565c013 build : Kotlin 테스트 라이브러리 추가 2022-04-24 18:35:04 +09:00
banjjoknim
e08fb7a55a refactor(UserTest) : 오탈자 수정 2022-04-24 18:31:31 +09:00
banjjoknim
8275e0be43 refactor(user.pojo) : 불필요한 테스트 삭제 2022-04-24 18:28:23 +09:00
Colt
d1db71b547 Merge branch 'main' into learn-with-making-clean-architecture 2022-04-24 18:19:21 +09:00
banjjoknim
ac51c21bd5 refactor : Nickname 입력 유효성 검사 ChangeNicknameRequest 에서 수행하도록 변경 2022-04-24 18:15:26 +09:00
banjjoknim
a8736fab0a docs(README.md) : 구현 항목 내용 추가 2022-04-24 17:52:22 +09:00
banjjoknim
0da78fab0f refactor : UserEntity @Table 이름 적용 2022-04-24 17:51:31 +09:00
banjjoknim
d588e84f47 refactor : adapter 계층만 application 계층에 의존하도록 통신 객체 추가 및 적용 2022-04-24 17:29:17 +09:00
banjjoknim
e1811f929c refactor : ChangeNicknameRequest, ChangeNicknameResponse 패키지 변경 2022-04-24 17:08:25 +09:00
banjjoknim
ba71d508ac docs(README.md) : 참고자료 및 구현 항목 내용 추가 2022-04-22 13:52:26 +09:00
banjjoknim
7505319c68 feat(user.adapter) : UserMapper 추가 및 적용 2022-04-22 13:29:42 +09:00
banjjoknim
6a523fb63f refactor : 패키지 구성 변경 2022-04-22 13:02:32 +09:00
banjjoknim
778e3b12ef docs(README.md) : 요구사항, 구현 항목 추가 2022-04-22 03:48:33 +09:00
banjjoknim
f691df5727 chore : Hexagonal Architecture Process 이미지 추가 2022-04-22 03:45:12 +09:00
banjjoknim
66fbb92908 feat : User Upsert Port 및 Adapter 구현, Service 로직에 추가 2022-04-22 03:44:22 +09:00
banjjoknim
5da53998dc refactor : User 닉네임 변경 기능 in port 이름 변경 2022-04-22 03:42:49 +09:00
banjjoknim
84854f5b74 refactor : User 닉네임 변경 기능 컴포넌트 이름 변경 2022-04-22 02:18:20 +09:00
banjjoknim
d9e5be3e9e refactor : 사용하지 않는 파일 삭제 2022-04-22 02:07:20 +09:00
banjjoknim
c81e058d41 refactor(user) : domain 패키지 내부 패키지 구성 추가 및 Entity, Model 이관 2022-04-22 02:07:07 +09:00
banjjoknim
821f057a7c feat : User 닉네임 변경 기능 추가 2022-04-22 02:04:36 +09:00
banjjoknim
255a97b223 feat(user.adapter) : User Entity 구현 2022-04-22 02:00:39 +09:00
banjjoknim
05c5fc07cc chore : DB 설정 추가 2022-04-22 01:59:45 +09:00
banjjoknim
7f06cf39b5 test(user.domain) : 회원 닉네임 변경 테스트 추가 2022-04-22 00:56:38 +09:00
banjjoknim
b7785205c0 refactor(User) : 닉네임 변경 함수 이름 수정 2022-04-22 00:42:44 +09:00
banjjoknim
b537b66fde feat(user.domain) : User 의 nickname 프로퍼티 값 객체로 포장 2022-04-22 00:41:56 +09:00
banjjoknim
8fbe74135f feat(user.domain) : 도메인 모델 User 추가 2022-04-22 00:38:25 +09:00
banjjoknim
207488c20e docs(README.md) : 내용 정리 추가 2022-04-19 04:02:03 +09:00
banjjoknim
00137fe4dc docs : README.md 헥사고날 아키텍처 항목 추가 2022-04-10 02:19:10 +09:00
banjjoknim
ee2cc32853 refactor : 프로젝트 진입점 클래스 이름 변경 2022-04-10 01:16:19 +09:00
banjjoknim
6e330292da 만들면서 배우는 클린 아키텍처 initial commit 2022-04-10 00:15:02 +09:00
10 changed files with 247 additions and 49 deletions

View File

@@ -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> {

View File

@@ -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)
}

View File

@@ -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() }
}
}
}
}

View File

@@ -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"))
}
}
}

View File

@@ -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"))
}
}
}

View File

@@ -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"))
}
}
}

View File

@@ -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"))
}
}
}

View File

@@ -1,24 +0,0 @@
package com.banjjoknim.cleanarchitecture.user.pojo
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.assertThrows
class NicknameTest {
@DisplayName("닉네임 생성 테스트")
@Nested
inner class ChangeNicknameTestCases {
@Test
fun `10글자 이내이면 닉네임을 생성할 수 있다`() {
assertDoesNotThrow { Nickname("banjjoknim") }
}
@Test
fun `10글자가 넘으면 닉네임을 생성할 경우 예외가 발생한다`() {
assertThrows<IllegalArgumentException> { Nickname("i'm banjjoknim") }
}
}
}

View File

@@ -7,7 +7,8 @@ import org.junit.jupiter.api.Test
class UserTest {
@DisplayName("회원 이름 변경 테스트 케이스")
@DisplayName("회원 닉네임 변경 테스트 케이스")
@Nested
inner class ChangeNicknameTestCases {
@Test

View File

@@ -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() {
}
}