본문 바로가기
서버/Kotlin-Spring_Boot

Kotlin-Spring_Boot 강의 정리) 10. DELETE Endpoint

by HDobby 2023. 2. 3.

https://youtu.be/aCuglaAfYm4

오늘은 마지막 엔드포인트인 DELETE Endpoint를 만들어 봅시다.

Delete 테스트 함수를 만들어 줍니다.

@Nested
	@DisplayName("DELETE /api/banks/{accountNumber}")
	@TestInstance(TestInstance.Lifecycle.PER_CLASS)
	inner class DeleteExistingBank {
		@Test
		fun `should delete the bank with the given account number`() {
			// given
			val accountNumber = 1234

			// when
			mockMvc.delete("$baseUrl/$accountNumber")

				// then
				.andDo { { print() } }
				.andExpect {
					status { isNoContent() }
				}

		}

	}

 

 

@DeleteMapping("/{accountNumber}")
	fun deleteBank(@PathVariable accountNumber: String): Unit {
	}

BankController에 Delete맵핑을 해줍니다.

Unit을 반환한다는건 void(반환이 없음)을 의미합니다.

테스트를 실행해봅시다.

204가 아닌 200이 왔다고 합니다.

이전에 PostMapping을 진행할 때 처럼 ResponseStatus를 설정해 줍시다.

@DeleteMapping("/{accountNumber}")
	@ResponseStatus(HttpStatus.NO_CONTENT)
	fun deleteBank(@PathVariable accountNumber: String): Unit {
	}

 

@Test
		fun `should delete the bank with the given account number`() {
			// given
			val accountNumber = 1234

			// when
			mockMvc.delete("$baseUrl/$accountNumber")

				// then
				.andDo { { print() } }
				.andExpect {
					status { isNoContent() }
				}

			mockMvc.get("$baseUrl/$accountNumber")
				.andExpect { status { isNotFound() } }
		}

그리고 정말 데이터가 없는지를 확인하기 위해 테스트에 확인하는 mockMvc.get을 추가해줍니다.

실행했더니 404가 아닌 200이 왔다고 합니다.

이제 함수를 수정해 줍시다.

 

BankController

package com.study.hello_world.controller

import com.study.hello_world.model.Bank
import com.study.hello_world.service.BankService
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/api/banks")
class BankController(private val service: BankService) {

	@ExceptionHandler(NoSuchElementException::class)
	fun handleNotFound(e: NoSuchElementException): ResponseEntity<String> =
		ResponseEntity(e.message, HttpStatus.NOT_FOUND)

	@ExceptionHandler(IllegalArgumentException::class)
	fun handleNotFound(e: IllegalArgumentException): ResponseEntity<String> =
		ResponseEntity(e.message, HttpStatus.BAD_REQUEST)

	@GetMapping
	fun helloWorld(): Collection<Bank> = service.getBanks()

	@GetMapping("/{accountNumber}")
	fun getBBank(@PathVariable accountNumber: String) = service.getBank(accountNumber)

	@PostMapping
	@ResponseStatus(HttpStatus.CREATED)
	fun addBank(@RequestBody bank: Bank): Bank = service.addBank(bank)

	@PatchMapping
	fun updateBank(@RequestBody bank: Bank): Bank = service.updateBank(bank)

	@DeleteMapping("/{accountNumber}")
	@ResponseStatus(HttpStatus.NO_CONTENT)
	fun deleteBank(@PathVariable accountNumber: String): Unit = service.deleteBank(accountNumber)
}

BankService

package com.study.hello_world.service

import com.study.hello_world.datasource.BankDataSource
import com.study.hello_world.model.Bank
import org.springframework.stereotype.Service

@Service
class BankService(private val dataSource: BankDataSource) {
	fun getBanks(): Collection<Bank> {
		return dataSource.retrieveBanks()
	}

	fun getBank(accountNumber: String): Bank = dataSource.retrieveBank(accountNumber)

	fun addBank(bank: Bank): Bank = dataSource.createBank(bank)

	fun updateBank(bank: Bank): Bank = dataSource.updateBank(bank)
	
	fun deleteBank(accountNumber: String): Unit = dataSource.deleteBank(accountNumber)
}

BankDataSource

package com.study.hello_world.datasource

import com.study.hello_world.model.Bank

interface BankDataSource {

	fun retrieveBanks(): Collection<Bank>

	fun retrieveBank(accountNumber: String): Bank

	fun createBank(bank: Bank): Bank

	fun updateBank(bank: Bank): Bank

	fun deleteBank(accountNumber: String)
}

MockBankDataSource

package com.study.hello_world.datasource.mock

import com.study.hello_world.datasource.BankDataSource
import com.study.hello_world.model.Bank
import org.springframework.stereotype.Repository

@Repository
class MockBankDataSource : BankDataSource {
	val banks = mutableListOf(
		Bank("1234", 3.14, 18),
		Bank("110", 17.0, 0),
		Bank("5678", 0.0, 100),
	)

	override fun retrieveBanks(): Collection<Bank> = banks

	override fun retrieveBank(accountNumber: String): Bank =
		banks.firstOrNull() { it.accountNumber == accountNumber }
			?: throw NoSuchElementException("Could not find a bank with account number $accountNumber aaa")

	override fun createBank(bank: Bank): Bank {
		if (banks.any { it.accountNumber == bank.accountNumber }) {
			throw IllegalArgumentException("Bank with account number ${bank.accountNumber} already exist")
		}
		banks.add(bank)

		return bank
	}

	override fun updateBank(bank: Bank): Bank {
		val currentBank = banks.firstOrNull { it.accountNumber == bank.accountNumber }
			?: throw NoSuchElementException("Could not find a bank with account number $bank.accountNumber aaa")

		banks.remove(currentBank)
		banks.add(bank)

		return bank
	}

	override fun deleteBank(accountNumber: String) {
		val currentBank = banks.firstOrNull { it.accountNumber == accountNumber }
			?: throw NoSuchElementException("Could not find a bank with account number $accountNumber aaa")

		banks.remove(currentBank)
	}
}

삭제하는 부분은 updateBank와 유사합니다.

새로운 계좌를 추가하는 부분과 return구문을 지워주시면 됩니다.

실행해 보시면 테스트를 성공적으로 통과하게 됩니다.

 

이번엔 없는 accountNumber를 주는 경우를 테스트 해 봅시다.

@Test
		fun `should return NOT FOUND if no bank with given account number exists`() {
			// given
			val invalidAccountNumber = "does_not_exist"

			// when
			mockMvc.delete("$baseUrl/$invalidAccountNumber")

				// then
				.andDo { print() }
				.andExpect { status { isNotFound() } }

		}

728x90

댓글