feat: implement application for testing

This commit is contained in:
이상진 2025-07-10 12:17:52 +09:00
parent 79dc26877e
commit 29a8e834b9
11 changed files with 239 additions and 42 deletions

View File

@ -33,6 +33,10 @@ dependencies {
runtimeOnly("com.h2database:h2")
runtimeOnly("com.mysql:mysql-connector-j")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
testImplementation("io.mockk:mockk:1.14.4")
testImplementation("io.kotest:kotest-runner-junit5:5.9.1")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")

View File

@ -0,0 +1,27 @@
package com.sangdol.demo
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
@RestController
class DataSourceLookupController(
private val properties: DataSourceProperties,
) {
@GetMapping("/dataSource")
fun lookup(): DataSourceInfoResponse = DataSourceInfoResponse(
properties.url,
properties.username,
properties.password,
properties.driverClassName
)
}
data class DataSourceInfoResponse(
val url: String,
val username: String,
val password: String,
val driverClassName: String,
)

View File

@ -0,0 +1,52 @@
package com.sangdol.demo
import org.springframework.web.bind.annotation.*
@RestController
@RequestMapping("/demo")
class DemoController(
private val demoService: DemoService
) {
@GetMapping
fun findAll(): List<FindResponse> = demoService.findAll()
@GetMapping("/{id}")
fun findById(
@PathVariable id: Long
): FindResponse = demoService.findById(id)
@PostMapping
fun create(
@RequestBody request: CreateRequest
): CreateResponse = demoService.create(request)
}
data class CreateRequest(
val name: String,
val age: Int,
)
fun CreateRequest.toEntity(): DemoEntity = DemoEntity(
name = this.name,
age = this.age
)
data class CreateResponse(
val id: Long,
)
fun DemoEntity.toCreateResponse(): CreateResponse = CreateResponse(
id = this.id ?: throw IllegalStateException("ID not generated"),
)
data class FindResponse(
val id: Long,
val name: String,
val age: Int
)
fun DemoEntity.toFindResponse(): FindResponse = FindResponse(
id = this.id ?: throw IllegalStateException("ID not generated"),
name = this.name,
age = this.age
)

View File

@ -0,0 +1,20 @@
package com.sangdol.demo
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.Table
@Entity
@Table(name = "demo")
class DemoEntity(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long? = null,
var name: String,
var age: Int,
)

View File

@ -0,0 +1,6 @@
package com.sangdol.demo
import org.springframework.data.jpa.repository.JpaRepository
interface DemoRepository : JpaRepository<DemoEntity, Long> {
}

View File

@ -0,0 +1,26 @@
package com.sangdol.demo
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.bind.annotation.RequestBody
@Service
class DemoService(
private val demoRepository: DemoRepository
) {
@Transactional(readOnly = true)
fun findAll(): List<FindResponse> = demoRepository.findAll()
.map { it.toFindResponse() }
@Transactional(readOnly = true)
fun findById(id: Long): FindResponse = demoRepository.findByIdOrNull(id)
?.toFindResponse()
?: throw IllegalArgumentException("Entity with id: $id not exist")
@Transactional
fun create(
@RequestBody request: CreateRequest
): CreateResponse = demoRepository.save(request.toEntity())
.toCreateResponse()
}

View File

@ -0,0 +1,8 @@
spring:
datasource:
driver-class-name: ${SPRING_DATASOURCE_DRIVER_CLASS_NAME}
url: ${SPRING_DATASOURCE_URL}
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}

View File

@ -0,0 +1,15 @@
spring:
datasource:
url: jdbc:h2:mem:test
username: sa
password:
driver-class-name: org.h2.Driver
jpa:
database-platform: org.hibernate.dialect.H2Dialect
show-sql: true
properties:
hibernate:
format_sql: true
h2:
console:
enabled: true

View File

@ -1,3 +1,12 @@
spring:
application:
name: argo-vault-demo
profiles:
active: ${SPRING_PROFILE:local}
jpa:
hibernate:
ddl-auto: none
defer-datasource-initialization: true
open-in-view: false

View File

@ -1,13 +0,0 @@
package com.sangdol.demo
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
@SpringBootTest
class DemoApplicationTests {
@Test
fun contextLoads() {
}
}

View File

@ -0,0 +1,43 @@
package com.sangdol.demo
import io.kotest.assertions.assertSoftly
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.BehaviorSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.mockk.every
import io.mockk.mockk
import org.springframework.data.repository.findByIdOrNull
internal class DemoServiceTest : BehaviorSpec({
val demoRepository: DemoRepository = mockk()
val demoService = DemoService(demoRepository)
Given("Entity를 ID로 조회할 때") {
val id: Long = 1L
When("입력된 ID로 조회되는 결과가 없다면") {
every { demoRepository.findByIdOrNull(id) } returns null
Then("IllegalArgumentException이 발생한다.") {
shouldThrow<IllegalArgumentException> { demoService.findById(id) }
}
}
When("입력된 ID로 조회되는 결과가 있다면") {
every { demoRepository.findByIdOrNull(id) } returns DemoEntity(id, "hello kotlin", 20)
Then("정상적으로 반환된다.") {
val result: FindResponse = demoService.findById(id)
result shouldNotBe null
assertSoftly(result) {
this.id shouldBe id
this.name shouldBe "hello kotlin"
this.age shouldBe 20
}
}
}
}
})