如何在 MockMvc 测试中接受两个不同的状态码?

问题描述 投票:0回答:3

我需要在集成测试中测试 HTTP 端点。有两种可接受的回应:

  • 状态代码 200,在这种情况下,我需要检查内容是否为 JSON 并在正文中查找特定的元素值,或者
  • 状态代码是 5xx,在这种情况下我什么都不做。 (目标是当我调用的服务没有响应时,我的测试不会失败。)

我知道如何分别测试每个可接受的响应。示例(Kotlin):

    mockMvc.get("/myresource") {
        contentType = MediaType.APPLICATION_JSON
        accept = MediaType.APPLICATION_JSON
    }.andExpect {
        status { isOk() }
        content { contentType(MediaType.APPLICATION_JSON) }
        jsonPath("$.greeting", `is`("Hello SO"))
    }

和:

    mockMvc.get("/myresource") {
        contentType = MediaType.APPLICATION_JSON
        accept = MediaType.APPLICATION_JSON
    }.andExpect {
        status { is5xxServerError() }
    }

如何在一次测试中结合两种可接受的回答?

我希望我不需要求助于

RestTemplate
.

spring-boot spring-mvc mockmvc
3个回答
1
投票

爪哇:

import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.oneOf;
import static org.hamcrest.Matchers.allOf;

mockMvc.stuff().andExpect(status().is(oneOf(200, 503)))

mockMvc.stuff()
       .andExpect(status().is(anyOf(allOf(lessThan(505), greaterThan(500)),
                                    allOf(lessThan(205), greaterThan(200)))));

is()
后面的
status()
这个。我写的不一定是使用 Hamcrest 匹配器(有 lot 可供选择)的最佳方法。此外,您最好自己编写。但这是一般的想法。


1
投票

不像接受两个状态码那么简单:根据实际状态,可能需要对内容和json路径做进一步的断言。所以这个场景比看起来更复杂,我怀疑内置

ResultMatchers
支持它。该场景还测试了两个 完全不同 结果的事实无助于在 spring-test 项目中添加此类支持。

也就是说,有一些方法可以建立有条件地执行断言的期望:

mockMvc.perform(get("/myresource"))
       .andExpect(status().is(anyOf(is(HttpStatus.OK), new CustomMatcher<>("status should be 5xx") {
           @Override
           public boolean matches(Object status) {
               return status instanceof Integer
                 && HttpStatus.Series.SERVER_ERROR.equals(HttpStatus.valueOf((int) status).series());
                }
            })))
       .andExpect(mvcResult -> {
                if (mvcResult.getResponse().getStatus() == HttpStatus.OK.value()) {
                    content().contentType(MediaType.APPLICATION_JSON).match(mvcResult);
                    jsonPath("$.greeting", is("Hello SO")).match(mvcResult);
                }
       })

这转化为:

  • 我希望状态为 200 或 5xx 错误,
  • 我希望如果状态正常,那么内容符合我的期望值

0
投票

根据 MA 和 neofelis 的回答(非常感谢!),我找到了解决方案(在 Kotlin 中)。

要求

  • 如果状态代码是任何 5xx,则测试应通过(忽略)。
  • 如果不是 5xx,应测试特定的 2xx 或 4xx 成功代码(一些测试期望 200,其他测试 201、202、404、422 等)。在这种情况下,还应测试响应的元素(正文、标题)。
  • 5xx 验证应可在多个测试和测试单元中重复使用。

解决方案

可重复使用

CustomMatcher
识别一个5xx状态码:

fun isServerError5xx() = IsServerError5xx()

class IsServerError5xx : CustomMatcher<Any?>("Check if status code is 5xx") {
    override fun matches(status: Any?): Boolean =
        if (status == null || status !is Int)
            false
        else
            HttpStatus.resolve(status)?.is5xxServerError == true
}

MockMvc
测试示例(使用 MockMvc DSL):

mockMvc.get("/myresource") {
    contentType = MediaType.APPLICATION_JSON
    accept = MediaType.APPLICATION_JSON
}.andExpect {
    status { `is`(anyOf(`is`(HttpStatus.OK.value()), isServerError5xx())) }
    match {
        if (it.response.status == HttpStatus.OK.value()) {
            content { contentType(MediaType.APPLICATION_JSON) }
            jsonPath("$.greeting", `is`("Hello SO"))
        }
    }
}

使用 MockMvc DSL 的相同示例not

mockMvc.perform(
    get(""/myresource"")
        .accept(MediaType.APPLICATION_JSON)
        .contentType(MediaType.APPLICATION_JSON)
)
    .andExpect(status().`is`(anyOf(`is`(HttpStatus.OK.value()), isServerError5xx())))
    .andExpect { mvcResult: MvcResult ->
        if (mvcResult.response.status == HttpStatus.OK.value()) {
            content().contentType(MediaType.APPLICATION_JSON).match(mvcResult)
            jsonPath("$.greeting", `is`("Hello SO"))
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.