add global exception handler for controllers

add new not found exception, add new test for ShopController
This commit is contained in:
Denis Savosin
2024-09-25 16:55:24 +07:00
parent 61e5e7cea6
commit 6247eedb9a
6 changed files with 69 additions and 15 deletions

View File

@@ -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(

View File

@@ -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)
}

View File

@@ -0,0 +1,3 @@
package com.example.demo.exceptions
class NotFoundException: RuntimeException()

View File

@@ -0,0 +1,5 @@
package com.example.demo.responses
class BaseResponse(val status: ResponseStatus)
fun makeNotFound(): BaseResponse = BaseResponse(status = ResponseStatus.NOT_FOUND)

View File

@@ -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");
}

View File

@@ -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,
)
}
} }