Skip to content
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
102 changes: 58 additions & 44 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
kotlin("jvm")
kotlin("kapt")
kotlin("plugin.spring") apply false
kotlin("plugin.jpa") apply false
id("org.springframework.boot") apply false
Expand All @@ -11,8 +8,6 @@ plugins {
id("org.jlleitschuh.gradle.ktlint") apply false
}

java.sourceCompatibility = JavaVersion.valueOf("VERSION_${property("javaVersion")}")

allprojects {
group = "${property("projectGroup")}"
version = "${property("applicationVersion")}"
Expand All @@ -24,7 +19,6 @@ allprojects {

subprojects {
apply(plugin = "org.jetbrains.kotlin.jvm")
apply(plugin = "org.jetbrains.kotlin.kapt")
apply(plugin = "org.jetbrains.kotlin.plugin.spring")
apply(plugin = "org.jetbrains.kotlin.plugin.jpa")
apply(plugin = "org.springframework.boot")
Expand All @@ -40,65 +34,85 @@ subprojects {

dependencies {
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("com.ninja-squad:springmockk:${property("springMockkVersion")}")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
kapt("org.springframework.boot:spring-boot-configuration-processor")
}

tasks.getByName("bootJar") {
enabled = false
}

tasks.getByName("jar") {
enabled = true
testImplementation("org.springframework.boot:spring-boot-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
testImplementation("org.assertj:assertj-core")
testImplementation("com.ninja-squad:springmockk:${property("springMockkVersion")}")
}

java.sourceCompatibility = JavaVersion.valueOf("VERSION_${property("javaVersion")}")
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "${project.property("javaVersion")}"
java {
toolchain {
languageVersion = JavaLanguageVersion.of("${property("javaVersion")}")
}
}

tasks.test {
useJUnitPlatform {
excludeTags("develop", "restdocs")
kotlin {
compilerOptions {
freeCompilerArgs.addAll("-Xjsr305=strict", "-Xannotation-default-target=param-property")
}
}

tasks.register<Test>("unitTest") {
group = "verification"
useJUnitPlatform {
excludeTags("develop", "context", "restdocs")
}
tasks.named<Jar>("bootJar").configure {
enabled = false
}

tasks.register<Test>("contextTest") {
group = "verification"
useJUnitPlatform {
includeTags("context")
}
tasks.named<Jar>("jar").configure {
enabled = true
}

tasks.register<Test>("restDocsTest") {
group = "verification"
tasks.test {
useJUnitPlatform {
includeTags("restdocs")
excludeTags("develop", "restdocs")
}
}

tasks.register<Test>("developTest") {
group = "verification"
useJUnitPlatform {
includeTags("develop")
testing {
suites {
named<JvmTestSuite>("test") {
targets {
register("unitTest") {
testTask.configure {
group = "verification"
useJUnitPlatform {
excludeTags("develop", "context", "restdocs")
}
}
}

register("contextTest") {
testTask.configure {
group = "verification"
useJUnitPlatform {
includeTags("context")
}
}
}

register("restDocsTest") {
testTask.configure {
group = "verification"
useJUnitPlatform {
includeTags("restdocs")
}
}
}

register("developTest") {
testTask.configure {
group = "verification"
useJUnitPlatform {
includeTags("develop")
}
}
}
}
}
}
}

tasks.getByName("asciidoctor") {
tasks.named("asciidoctor").configure {
dependsOn("restDocsTest")
}
}
6 changes: 3 additions & 3 deletions core/core-api/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
tasks.getByName("bootJar") {
tasks.named<Jar>("bootJar").configure {
enabled = true
}

tasks.getByName("jar") {
tasks.named<Jar>("jar").configure {
enabled = false
}

Expand All @@ -15,5 +15,5 @@ dependencies {

testImplementation(project(":tests:api-docs"))

implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-webmvc")
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import java.util.concurrent.Executor
@Configuration
@EnableAsync
class AsyncConfig : AsyncConfigurer {

@Bean
override fun getAsyncExecutor(): Executor {
val executor = ThreadPoolTaskExecutor()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.dodn.springboot.core.api.controller.v1

import io.dodn.springboot.core.api.controller.v1.request.ExampleRequestDto
import io.dodn.springboot.core.api.controller.v1.response.ExampleItemResponseDto
import io.dodn.springboot.core.api.controller.v1.response.ExampleResponseDto
import io.dodn.springboot.core.domain.ExampleData
import io.dodn.springboot.core.domain.ExampleService
Expand All @@ -11,6 +12,8 @@ import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import java.time.LocalDate
import java.time.LocalDateTime

@RestController
class ExampleController(
Expand All @@ -22,14 +25,14 @@ class ExampleController(
@RequestParam exampleParam: String,
): ApiResponse<ExampleResponseDto> {
val result = exampleExampleService.processExample(ExampleData(exampleValue, exampleParam))
return ApiResponse.success(ExampleResponseDto(result.data))
return ApiResponse.success(ExampleResponseDto(result.data, LocalDate.now(), LocalDateTime.now(), ExampleItemResponseDto.build()))
}

@PostMapping("/post")
fun examplePost(
@RequestBody request: ExampleRequestDto,
): ApiResponse<ExampleResponseDto> {
val result = exampleExampleService.processExample(request.toExampleData())
return ApiResponse.success(ExampleResponseDto(result.data))
return ApiResponse.success(ExampleResponseDto(result.data, LocalDate.now(), LocalDateTime.now(), ExampleItemResponseDto.build()))
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
package io.dodn.springboot.core.api.controller.v1.response

import java.time.LocalDate
import java.time.LocalDateTime

data class ExampleResponseDto(
val result: String,
val date: LocalDate,
val datetime: LocalDateTime,
val items: List<ExampleItemResponseDto>,
)

data class ExampleItemResponseDto(
val key: String,
) {
companion object {
fun build(): List<ExampleItemResponseDto> {
return listOf(ExampleItemResponseDto("1"), ExampleItemResponseDto("2"))
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.dodn.springboot.core.support.error

data class ErrorMessage private constructor(
class ErrorMessage private constructor(
val code: String,
val message: String,
val data: Any? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package io.dodn.springboot.core.support.response
import io.dodn.springboot.core.support.error.ErrorMessage
import io.dodn.springboot.core.support.error.ErrorType

data class ApiResponse<T> private constructor(
class ApiResponse<T> private constructor(
val result: ResultType,
val data: T? = null,
val error: ErrorMessage? = null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,52 +1,52 @@
package io.dodn.springboot.core.api.controller.v1

import com.fasterxml.jackson.module.kotlin.jsonMapper
import io.dodn.springboot.core.api.controller.v1.request.ExampleRequestDto
import io.dodn.springboot.core.domain.ExampleResult
import io.dodn.springboot.core.domain.ExampleService
import io.dodn.springboot.test.api.RestDocsTest
import io.dodn.springboot.test.api.RestDocsUtils.requestPreprocessor
import io.dodn.springboot.test.api.RestDocsUtils.responsePreprocessor
import io.mockk.every
import io.mockk.mockk
import io.restassured.http.ContentType
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document
import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get
import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post
import org.springframework.restdocs.operation.preprocess.Preprocessors
import org.springframework.restdocs.payload.JsonFieldType
import org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath
import org.springframework.restdocs.payload.PayloadDocumentation.requestFields
import org.springframework.restdocs.payload.PayloadDocumentation.responseFields
import org.springframework.restdocs.request.RequestDocumentation
import org.springframework.restdocs.request.RequestDocumentation.parameterWithName
import org.springframework.restdocs.request.RequestDocumentation.queryParameters
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status

class ExampleControllerTest : RestDocsTest() {
private lateinit var exampleService: ExampleService
private lateinit var controller: ExampleController

@BeforeEach
fun setUp() {
exampleService = mockk()
controller = ExampleController(exampleService)
mockMvc = mockController(controller)
mockMvc = mockController(ExampleController(exampleService))
}

@Test
fun exampleGet() {
every { exampleService.processExample(any()) } returns ExampleResult("BYE")
every { exampleService.processExample(any()) } returns ExampleResult("BYE_GET")

given()
.contentType(ContentType.JSON)
.queryParam("exampleParam", "HELLO_PARAM")
.get("/get/{exampleValue}", "HELLO_PATH")
.then()
.status(HttpStatus.OK)
.apply(
mockMvc.perform(
get("/get/{exampleValue}", "HELLO_PATH")
.param("exampleParam", "HELLO_PARAM")
.contentType(MediaType.APPLICATION_JSON),
)
.andExpect(status().isOk)
.andDo(
document(
"exampleGet",
requestPreprocessor(),
responsePreprocessor(),
Preprocessors.preprocessRequest(Preprocessors.prettyPrint()),
Preprocessors.preprocessResponse(Preprocessors.prettyPrint()),
RequestDocumentation.pathParameters(
parameterWithName("exampleValue").description("ExampleValue"),
),
Expand All @@ -55,7 +55,11 @@ class ExampleControllerTest : RestDocsTest() {
),
responseFields(
fieldWithPath("result").type(JsonFieldType.STRING).description("ResultType"),
fieldWithPath("data.result").type(JsonFieldType.STRING).description("Result Date"),
fieldWithPath("data.result").type(JsonFieldType.STRING).description("Result Data"),
fieldWithPath("data.date").type(JsonFieldType.STRING).description("Result Date"),
fieldWithPath("data.datetime").type(JsonFieldType.STRING).description("Result Datetime"),
fieldWithPath("data.items").type(JsonFieldType.ARRAY).description("Result Items"),
fieldWithPath("data.items[].key").type(JsonFieldType.STRING).description("Result Item"),
fieldWithPath("error").type(JsonFieldType.NULL).ignored(),
),
),
Expand All @@ -64,25 +68,29 @@ class ExampleControllerTest : RestDocsTest() {

@Test
fun examplePost() {
every { exampleService.processExample(any()) } returns ExampleResult("BYE")
every { exampleService.processExample(any()) } returns ExampleResult("BYE_POST")

given()
.contentType(ContentType.JSON)
.body(ExampleRequestDto("HELLO_BODY"))
.post("/post")
.then()
.status(HttpStatus.OK)
.apply(
mockMvc.perform(
post("/post")
.contentType(MediaType.APPLICATION_JSON)
.content(jsonMapper().writeValueAsString(ExampleRequestDto("HELLO_BODY"))),
)
.andExpect(status().isOk)
.andDo(
document(
"examplePost",
requestPreprocessor(),
responsePreprocessor(),
Preprocessors.preprocessRequest(Preprocessors.prettyPrint()),
Preprocessors.preprocessResponse(Preprocessors.prettyPrint()),
requestFields(
fieldWithPath("data").type(JsonFieldType.STRING).description("ExampleBody Data Field"),
),
responseFields(
fieldWithPath("result").type(JsonFieldType.STRING).description("ResultType"),
fieldWithPath("data.result").type(JsonFieldType.STRING).description("Result Date"),
fieldWithPath("data.result").type(JsonFieldType.STRING).description("Result Data"),
fieldWithPath("data.date").type(JsonFieldType.STRING).description("Result Date"),
fieldWithPath("data.datetime").type(JsonFieldType.STRING).description("Result Datetime"),
fieldWithPath("data.items").type(JsonFieldType.ARRAY).description("Result Items"),
fieldWithPath("data.items[].key").type(JsonFieldType.STRING).description("Result Item"),
fieldWithPath("error").type(JsonFieldType.STRING).ignored(),
),
),
Expand Down
14 changes: 7 additions & 7 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ applicationVersion=0.0.1-SNAPSHOT
projectGroup=io.dodn.springboot

### Project dependency versions ###
kotlinVersion=1.9.25
kotlinVersion=2.2.21
javaVersion=21

### Plugin dependency versions ###
asciidoctorConvertVersion=3.3.2
ktlintVersion=13.0.0
asciidoctorConvertVersion=4.0.5
ktlintVersion=14.0.1

### Spring dependency versions ###
springBootVersion=3.5.3
springBootVersion=4.0.0
springDependencyManagementVersion=1.1.7
springCloudDependenciesVersion=2025.0.0
springCloudDependenciesVersion=2025.1.0

### External dependency versions ###
springMockkVersion=4.0.2
sentryVersion=8.17.0
springMockkVersion=5.0.1
sentryVersion=8.27.1
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
Loading
Loading