mirror of
https://github.com/Dannecron/spring-boot-demo.git
synced 2025-12-26 00:32:34 +03:00
add global exception handler for controllers
add new not found exception, add new test for ShopController
This commit is contained in:
@@ -1,11 +1,11 @@
|
|||||||
package com.example.demo.controllers
|
package com.example.demo.controllers
|
||||||
|
|
||||||
|
import com.example.demo.exceptions.NotFoundException
|
||||||
import com.example.demo.provider.ShopProvider
|
import com.example.demo.provider.ShopProvider
|
||||||
import jakarta.servlet.http.HttpServletResponse
|
import jakarta.servlet.http.HttpServletResponse
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.encodeToJsonElement
|
import kotlinx.serialization.json.encodeToJsonElement
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.http.HttpStatus
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
import org.springframework.web.bind.annotation.ResponseBody
|
import org.springframework.web.bind.annotation.ResponseBody
|
||||||
import org.springframework.web.bind.annotation.RestController
|
import org.springframework.web.bind.annotation.RestController
|
||||||
@@ -16,14 +16,9 @@ class ShopController (
|
|||||||
) {
|
) {
|
||||||
@GetMapping(value = ["/shop/common-info"], produces = ["application/json"])
|
@GetMapping(value = ["/shop/common-info"], produces = ["application/json"])
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
|
@Throws(NotFoundException::class)
|
||||||
fun commonInfo(response: HttpServletResponse): String {
|
fun commonInfo(response: HttpServletResponse): String {
|
||||||
val shop = shopProvider.getRandomShop()
|
val shop = shopProvider.getRandomShop() ?: throw NotFoundException()
|
||||||
|
|
||||||
if (shop == null) {
|
|
||||||
response.status = HttpStatus.NOT_FOUND.value()
|
|
||||||
|
|
||||||
return "not found"
|
|
||||||
}
|
|
||||||
|
|
||||||
return Json.encodeToJsonElement(value = mapOf(
|
return Json.encodeToJsonElement(value = mapOf(
|
||||||
"customers" to mapOf(
|
"customers" to mapOf(
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.example.demo.exceptions
|
||||||
|
|
||||||
|
import com.example.demo.responses.makeNotFound
|
||||||
|
import org.springframework.http.HttpStatus
|
||||||
|
import org.springframework.http.ResponseEntity
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler
|
||||||
|
|
||||||
|
@ControllerAdvice
|
||||||
|
class ExceptionHandler {
|
||||||
|
@ExceptionHandler(NotFoundException::class)
|
||||||
|
fun handleNotFound(): ResponseEntity<Any> = ResponseEntity(makeNotFound(), HttpStatus.NOT_FOUND)
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package com.example.demo.exceptions
|
||||||
|
|
||||||
|
class NotFoundException: RuntimeException()
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.example.demo.responses
|
||||||
|
|
||||||
|
class BaseResponse(val status: ResponseStatus)
|
||||||
|
|
||||||
|
fun makeNotFound(): BaseResponse = BaseResponse(status = ResponseStatus.NOT_FOUND)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.example.demo.responses
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonValue
|
||||||
|
|
||||||
|
enum class ResponseStatus(@JsonValue val status: String) {
|
||||||
|
NOT_FOUND("not found");
|
||||||
|
}
|
||||||
@@ -11,6 +11,8 @@ import org.springframework.test.web.servlet.MockMvc
|
|||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
|
||||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
|
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
|
||||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.util.*
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|
||||||
@WebMvcTest(ShopController::class)
|
@WebMvcTest(ShopController::class)
|
||||||
@@ -20,30 +22,35 @@ class ShopControllerTest(@Autowired val mockMvc: MockMvc) {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun commonInfo_shouldSeeSuccessResponseJson() {
|
fun commonInfo_shouldSeeSuccessResponseJson() {
|
||||||
|
val productOne = makeProduct(id = 1, name = "one", price = 11.2)
|
||||||
|
val productTwo = makeProduct(id = 2, name = "two", price = 13.2)
|
||||||
|
val productThree = makeProduct(id = 3, name = "three", price = 15.2)
|
||||||
|
val productFour = makeProduct(id = 4, name = "four", price = 14.2)
|
||||||
|
|
||||||
val shopMock = Shop(name="shop", customers= listOf(
|
val shopMock = Shop(name="shop", customers= listOf(
|
||||||
Customer(
|
Customer(
|
||||||
name = "cus-one",
|
name = "cus-one",
|
||||||
city = City(name= "city-one"),
|
city = City(name= "city-one"),
|
||||||
orders = listOf(
|
orders = listOf(
|
||||||
Order(products = listOf(Product(name = "one", price = 11.2)), isDelivered = false),
|
Order(products = listOf(productOne), isDelivered = false),
|
||||||
Order(products = listOf(Product(name = "two", price = 13.2)), isDelivered = false),
|
Order(products = listOf(productTwo), isDelivered = false),
|
||||||
Order(products = listOf(Product(name = "three", price = 15.2)), isDelivered = true),
|
Order(products = listOf(productThree), isDelivered = true),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
Customer(
|
Customer(
|
||||||
name = "cus-two",
|
name = "cus-two",
|
||||||
city = City(name= "city-two"),
|
city = City(name= "city-two"),
|
||||||
orders = listOf(
|
orders = listOf(
|
||||||
Order(products = listOf(Product(name = "one", price = 12.2)), isDelivered = false),
|
Order(products = listOf(productOne), isDelivered = false),
|
||||||
Order(products = listOf(Product(name = "two", price = 13.2)), isDelivered = true),
|
Order(products = listOf(productTwo), isDelivered = true),
|
||||||
Order(products = listOf(Product(name = "four", price = 14.2)), isDelivered = true),
|
Order(products = listOf(productFour), isDelivered = true),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
|
|
||||||
val expectedJson: String = """{
|
val expectedJson: String = """{
|
||||||
|"customers": {"withMoreUndeliveredOrdersThanDelivered": ["cus-one"]},
|
|"customers": {"withMoreUndeliveredOrdersThanDelivered": ["cus-one"]},
|
||||||
|"products": {"orderedByAllCustomers": ["two"]}
|
|"products": {"orderedByAllCustomers": ["one", "two"]}
|
||||||
|}""".trimMargin()
|
|}""".trimMargin()
|
||||||
|
|
||||||
whenever(
|
whenever(
|
||||||
@@ -55,4 +62,28 @@ class ShopControllerTest(@Autowired val mockMvc: MockMvc) {
|
|||||||
.andExpect(content().contentType("application/json"))
|
.andExpect(content().contentType("application/json"))
|
||||||
.andExpect(content().json(expectedJson))
|
.andExpect(content().json(expectedJson))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun commonInfo_shouldSeeNotFoundResponse() {
|
||||||
|
whenever(
|
||||||
|
shopProvider.getRandomShop()
|
||||||
|
) doReturn (null)
|
||||||
|
|
||||||
|
mockMvc.perform(get("/shop/common-info"))
|
||||||
|
.andExpect(status().isNotFound)
|
||||||
|
.andExpect(content().contentType("application/json"))
|
||||||
|
.andExpect(content().json("""{"status":"not found"}"""))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeProduct(id: Long, name: String, price: Double): Product {
|
||||||
|
return Product(
|
||||||
|
id = id,
|
||||||
|
guid = UUID.randomUUID(),
|
||||||
|
name = name,
|
||||||
|
description = null,
|
||||||
|
price = (price * 100).toInt(),
|
||||||
|
createdAt = OffsetDateTime.now(),
|
||||||
|
updatedAt = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user