MockMvc Kotlin DSL
1. Visão geral
Neste tutorial rápido, daremos uma olhada no novo suporte específico para KotlinMockMvc disponível no Spring Framework 5.2+.
Nota: como a versão 5.2 ainda não é GA, precisamos usar SpringMilestone repository.
2. O controlador para testar
Vamos configurar o controlador que iremos testar.
Usaremos o seguinte domínio:
// Payload
data class Name(val first: String, val last: String)
// Web request
data class Request(val name: Name)
// Web response
@JsonInclude(JsonInclude.Include.NON_NULL) data class Response(val error: String?)
E um controlador REST que valida a carga útil que recebe:
@RestController
@RequestMapping("/mockmvc")
class MockMvcController {
@RequestMapping(value = ["/validate"], method = [RequestMethod.POST],
produces = [MediaType.APPLICATION_JSON_VALUE])
fun validate(@RequestBody request: Request): Response {
val error = if (request.name.first == "admin") {
null
} else {
ERROR
}
return Response(error)
}
companion object {
const val ERROR = "invalid user"
}
}
Aqui, temos um endpoint POST que recebe uma instância de nossa classeRequest personalizada serializada para JSON e retorna uma instância de nossa classeResponse personalizada serializada para JSON.
3. Abordagem de teste clássico
Podemos testar o controlador acima usando a abordagem padrãoMockMvc:
mockMvc.perform(MockMvcRequestBuilders
.post("/mockmvc/validate")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(Request(Name("admin", "")))))
.andExpect(MockMvcResultMatchers.status().isOk)
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.content().string("{}"))
No exemplo acima, usamos o suporte de teste padrão para verificar alguns aspectos:
-
o código de resposta HTTP é 200
-
o tipo de conteúdo da resposta éapplication/json
-
o conteúdo da resposta é um objeto JSON vazio
Na verdade, parece muito bom - limpo e expressivo. Maswe can make it even cleaner with Kotlin DSL.
4. Abordagem de teste moderna
O mesmo teste pode ser reescrito como:
mockMvc.post("/mockmvc/validate") {
contentType = MediaType.APPLICATION_JSON
content = mapper.writeValueAsString(Request(Name("admin", "")))
accept = MediaType.APPLICATION_JSON
}.andExpect {
status { isOk }
content { contentType(MediaType.APPLICATION_JSON) }
content { json("{}") }
}
Vamos verificar como isso é implementado. Em primeiro lugar, precisamos usar o Spring Framework 5.2+, que contémMockMvcExtensions.kt — a custom DSL for MockMvc.
Começamos chamando a função de extensãoMockMvc.post() com umMockHttpServletRequestDslextension method:
mockMvc.post("/mockmvc/validate") {
// This is extension method's body
}
Isso significa que o método é executado com um objetoMockHttpServletRequestDsl como referênciathis, então acabamos de definir suas propriedadescontentType,content eaccept.
Em seguida, definimos as expectativas de maneira semelhante - fornecendo um método de extensãoMockMvcResultMatchersDsl:
andExpect {
// Extension method body
}
5. Evolução adicional
Se quisermos adicionar mais testes, podemos refatorar o código existente para evitar duplicação.
Vamos extrair o código comum aqui em um métododoTest útil:
private fun doTest(input: Request, expectation: Response) {
mockMvc.post("/mockmvc/validate") {
contentType = MediaType.APPLICATION_JSON
content = mapper.writeValueAsString(input)
accept = MediaType.APPLICATION_JSON
}.andExpect {
status { isOk }
content { contentType(MediaType.APPLICATION_JSON) }
content { json(mapper.writeValueAsString(expectation)) }
}
}
Agora, os testes reais serão simplificados:
@Test
fun `when supported user is given then validation is successful`() {
doTest(Request(Name("admin", "")), Response(null))
}
@Test
fun `when unsupported user is given then validation is failed`() {
doTest(Request(Name("some-name", "some-surname")), Response(MockMvcController.ERROR))
}
6. Conclusão
Neste artigo, verificamos comoMockMvc Kotlin DSL pode ser usado para tornar nosso código de teste mais limpo. Não é uma solução mágica, apenas um pequeno recurso que torna o código de teste ainda mais conciso.
Como este é mais um exemplo de uso de DSL personalizado, ele pode servir como motivação para começar a usar DSL personalizado em outros projetos também.
Como de costume, o código-fonte completo deste artigo está disponívelover on GitHub.