Skip to content

Commit

Permalink
importフォーマット崩れ対応
Browse files Browse the repository at this point in the history
  • Loading branch information
rami2076 committed Oct 5, 2023
1 parent aa84113 commit 29b1e3d
Show file tree
Hide file tree
Showing 5 changed files with 334 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.kotlinonspringboot.domain.usecase

import com.example.kotlinonspringboot.domain.model.Employee

interface EmployeeUpdateUseCase {

/**
* 更新ユースケース
* @param willRenewEmployee 更新予定社員
* @return 常にtrue
*/
fun update(willRenewEmployee: Employee.WillRenewEmployee): Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.example.kotlinonspringboot.domain.model.EmployeeNumber
import com.example.kotlinonspringboot.domain.model.condition.DeleteCondition
import com.example.kotlinonspringboot.domain.usecase.EmployeeDeleteUseCase
import com.example.kotlinonspringboot.domain.usecase.EmployeeRegisterUseCase
import com.example.kotlinonspringboot.domain.usecase.EmployeeUpdateUseCase
import com.example.kotlinonspringboot.presentation.api.EmployeeUpdateApi
import com.example.kotlinonspringboot.presentation.model.EmployeeRegisterRequest
import com.example.kotlinonspringboot.presentation.model.EmployeeUpdateRequest
Expand All @@ -16,7 +17,8 @@ import java.math.BigDecimal
@RestController
class EmployeeUpdateController(
private val employeeDeleteUseCase: EmployeeDeleteUseCase,
private val employeeRegisterUseCase: EmployeeRegisterUseCase
private val employeeRegisterUseCase: EmployeeRegisterUseCase,
private val employeeUpdateUseCase: EmployeeUpdateUseCase
) : EmployeeUpdateApi {

override fun register(employeeRegisterRequest: EmployeeRegisterRequest): ResponseEntity<Unit> {
Expand All @@ -43,6 +45,18 @@ class EmployeeUpdateController(
}

override fun update(employeeUpdateRequest: EmployeeUpdateRequest): ResponseEntity<Unit> {
return ResponseEntity.noContent().build()
// 変換
val (employeeNumber, fullName, age, emailAddress) = employeeUpdateRequest.employee
val willRenewEmployee =
Employee.WillRenewEmployee(
employeeNumber = EmployeeNumber(employeeNumber.toLong()),
fullName = fullName,
age = age.shortValueExact(),
emailAddress = emailAddress
)

employeeUpdateUseCase.update(willRenewEmployee)

return ResponseEntity.status(HttpStatus.NO_CONTENT).build()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.kotlinonspringboot.usecase

import com.example.kotlinonspringboot.domain.model.Employee
import com.example.kotlinonspringboot.domain.usecase.EmployeeUpdateUseCase
import org.springframework.stereotype.Service

@Service
class EmployeeUpdateUseCaseImpl : EmployeeUpdateUseCase {

/**
* 更新ユースケース
* @param willRenewEmployee 更新予定社員
* @return 常にtrue
*/
override fun update(willRenewEmployee: Employee.WillRenewEmployee): Boolean {
return true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
package com.example.kotlinonspringboot.presentation.controller

import com.example.kotlinonspringboot.domain.model.EmployeeServiceException
import com.example.kotlinonspringboot.domain.usecase.EmployeeUpdateUseCase
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.junit.jupiter.api.TestInstance
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.MethodSource
import org.mockito.kotlin.any
import org.mockito.kotlin.doThrow
import org.mockito.kotlin.whenever
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.http.MediaType
import org.springframework.test.web.reactive.server.WebTestClient

import java.util.stream.Stream

/**
* メソッドが多いのでテストクラスを分割している
*/
@SpringBootTest
@AutoConfigureMockMvc
@DisplayName("PK社員更新コントローラのテスト")
class UpdateInEmployeeUpdateControllerTest {

@MockBean
private lateinit var employeeUpdateUseCase: EmployeeUpdateUseCase

@BeforeEach
fun setUp() {
// 準備
// 社員更新ユースケースからの返却を定義
whenever(employeeUpdateUseCase.update(any())).thenReturn(true)
}

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Nested
@DisplayName("社員更新")
inner class Update {

@Test
@DisplayName("更新時に、例外が発生しない場合は204を返却する")
fun test1(@Autowired webClient: WebTestClient) {
// 実行 & 検証
webClient.put().uri("/api/v1/employee")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(
"""
{
"employee": {
"employee_number": 1,
"full_name": "full_name",
"age": 20,
"email_address": "[email protected]"
}
}
""".trimIndent()
).exchange()
.expectStatus().isNoContent
}

@Test
@DisplayName("社員データソース例外が発生した場合、ステータス500をが返却すること")
fun test2(@Autowired webClient: WebTestClient) {
// 準備
// 社員更新ユースケースからの返却を定義
val runtimeException = RuntimeException("something error message")
val exception = EmployeeServiceException.EmployeeDataSourceException(runtimeException)
whenever(employeeUpdateUseCase.update(any())).doThrow(exception)

// 実行 & 検証
webClient.put().uri("/api/v1/employee")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(
"""
{
"employee": {
"employee_number": 1,
"full_name": "full_name",
"age": 20,
"email_address": "[email protected]"
}
}
""".trimIndent()
).exchange()
.expectStatus().is5xxServerError
.expectStatus().isEqualTo(500)
.expectBody().json(
"""
{
"message": "databaseで予期しない例外が発生しました"
}"""
)
}

@Test
@DisplayName("社員該当なし例外が発生した場合、ステータス410をが返却すること")
fun test2_1(@Autowired webClient: WebTestClient) {
// 準備
// 社員更新ユースケースからの返却を定義
val runtimeException = RuntimeException("something error message")
val exception = EmployeeServiceException.EmployeeUpdateNotApplicableException(runtimeException)
whenever(employeeUpdateUseCase.update(any())).doThrow(exception)

// 実行 & 検証
webClient.put().uri("/api/v1/employee")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(
"""
{
"employee": {
"employee_number": 1,
"full_name": "full_name",
"age": 20,
"email_address": "[email protected]"
}
}
""".trimIndent()
).exchange()
.expectStatus().isEqualTo(410)
.expectBody().json(
"""
{
"message": "社員更新中に対象の番号の社員が該当しませんでした"
}"""
)
}

@ParameterizedTest(name = "番号が[{0}]の時ステータス{2}を返却すること")
@DisplayName("番号の網羅試験")
@MethodSource("test3_0Source")
fun test3_0(
description: String,
employeeNumber: String,
httpStatus: Int,
@Autowired webClient: WebTestClient
) {
// 実行 & 検証
webClient.put().uri("/api/v1/employee")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(
"""
{
"employee": {
"employee_number": $employeeNumber,
"full_name": "full_name",
"age": 20,
"email_address": "[email protected]"
}
}
""".trimIndent()
).exchange()
.expectStatus().isEqualTo(httpStatus)
}

private fun test3_0Source(): Stream<Arguments> {
return Stream.of(
Arguments.of("閾値最小", "0", 204),
Arguments.of("閾値最大", "999999999", 204),
Arguments.of("閾値超過", "1000000000", 400),
Arguments.of("閾値未満", "-1", 400),
Arguments.of("形式エラー", "\"a\"", 400)
)
}

@ParameterizedTest(name = "氏名が[{0}]の時ステータス{2}を返却すること")
@DisplayName("氏名の網羅試験")
@MethodSource("test3Source")
fun test3(
description: String,
fullName: String,
httpStatus: Int,
@Autowired webClient: WebTestClient
) {
// 実行 & 検証
webClient.put().uri("/api/v1/employee")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(
"""
{
"employee": {
"employee_number": 1,
"full_name": "$fullName",
"age": 20,
"email_address": "[email protected]"
}
}
""".trimIndent()
).exchange()
.expectStatus().isEqualTo(httpStatus)
}

private fun test3Source(): Stream<Arguments> {
return Stream.of(
Arguments.of("閾値最小", "1".repeat(2), 204),
Arguments.of("閾値最大", "1".repeat(100), 204),
Arguments.of("閾値超過", "1".repeat(101), 400),
Arguments.of("閾値未満", "1".repeat(1), 400)
)
}

@ParameterizedTest(name = "年齢が[{0}]の時ステータス{2}を返却すること")
@DisplayName("年齢の網羅試験")
@MethodSource("test4Source")
fun test4(
description: String,
age: String,
httpStatus: Int,
@Autowired webClient: WebTestClient
) {
// 実行 & 検証
webClient.put().uri("/api/v1/employee")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(
"""
{
"employee": {
"employee_number": 1,
"full_name": "full_Name",
"age": $age,
"email_address": "[email protected]"
}
}
""".trimIndent()
).exchange()
.expectStatus().isEqualTo(httpStatus)
}

private fun test4Source(): Stream<Arguments> {
return Stream.of(
Arguments.of("閾値最小", "0", 204),
Arguments.of("閾値最大", "200", 204),
Arguments.of("閾値超過", "201", 400),
Arguments.of("閾値未満", "-1", 400)
)
}

@ParameterizedTest(name = "メールアドレスが[{0}]の時ステータス{2}を返却すること")
@DisplayName("メールアドレスの網羅試験")
@MethodSource("test5Source")
fun test5(
description: String,
emailAddress: String,
httpStatus: Int,
@Autowired webClient: WebTestClient
) {
// 実行 & 検証
webClient.put().uri("/api/v1/employee")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(
"""
{
"employee": {
"employee_number": 1,
"full_name": "full_Name",
"age": 20,
"email_address": "$emailAddress"
}
}
""".trimIndent()
).exchange()
.expectStatus().isEqualTo(httpStatus)
}

private fun test5Source(): Stream<Arguments> {
return Stream.of(
Arguments.of("閾値最小(10)", "[email protected]", 204),
Arguments.of("閾値未満(9)", "a@exapple", 400),
Arguments.of("使用可能文字", "abcdefghijklmnopqrstuvwxyz1234567890-_@exapple", 204)
)
}
}
}
8 changes: 7 additions & 1 deletion todo_it.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,10 @@
- [ ] /v1/employeeに社員登録リクエストをHTTPのPOSTメソッドでリクエストし成功した場合
- [x] HTTPステータス201が返却されること
- [ ] 登録されていること
- [ ] 500系 DB接続エラー
- [x] 500系 DB接続エラー
- [x] 番号が存在しない社員を更新しようとした場合、社員該当なし例外が発生して、410を返却すること
- [x] 例外がなく、更新できる場合、204を返却すること
- [x] 番号の網羅試験 UTで実施
- [x] 氏名の網羅試験 UTで実施
- [x] 年齢の網羅試験 UTで実施
- [x] メールアドレスの網羅試験 UTで実施

0 comments on commit 29b1e3d

Please sign in to comment.