You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MockRestServiceServer如何仅验证请求路径(排除查询字符串)

问题原因

Spring Boot 2.6.0对应的Spring Test版本中,MockRestRequestMatchers.requestTo()的字符串入参重载默认执行完整URL匹配,会把查询字符串也纳入校验范围,所以你传入不带查询参数的路径时会匹配失败。

最优解决方案

自定义Hamcrest Matcher,仅校验URI的scheme、host、port、path核心部分,忽略查询参数和锚点,完全满足路径精确匹配的需求,同时把查询参数的校验交给专门的queryParam()方法处理:

步骤1:定义通用路径匹配Matcher

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Objects;

public class UriPathMatcher extends BaseMatcher<String> {
    private final String expectedBaseUri;

    private UriPathMatcher(String expectedBaseUri) {
        this.expectedBaseUri = expectedBaseUri;
    }

    public static UriPathMatcher uriPathEquals(String expectedBaseUri) {
        return new UriPathMatcher(expectedBaseUri);
    }

    @Override
    public boolean matches(Object actual) {
        if (!(actual instanceof String actualUrl)) return false;
        try {
            URI actualUri = new URI(actualUrl);
            URI expectedUri = new URI(expectedBaseUri);
            return Objects.equals(actualUri.getScheme(), expectedUri.getScheme())
                    && Objects.equals(actualUri.getHost(), expectedUri.getHost())
                    && actualUri.getPort() == expectedUri.getPort()
                    && Objects.equals(actualUri.getPath(), expectedUri.getPath());
        } catch (URISyntaxException e) {
            return false;
        }
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("URI path equals to: " + expectedBaseUri);
    }
}

步骤2:修改测试代码调用Matcher

import static 你的包名.UriPathMatcher.uriPathEquals;

@Test
void testApiCall() {
    mockRestServiceServer.expect(MockRestRequestMatchers.requestTo(uriPathEquals(OBJECT_ID_URI)))
            .andExpect(MockRestRequestMatchers.method(HttpMethod.GET))
            .andExpect(MockRestRequestMatchers.queryParam("keyid", CoreMatchers.anything()))
            .andExpect(MockRestRequestMatchers.queryParam("token", CoreMatchers.anything()))
            .andRespond(MockRestResponseCreators.withSuccess("dummy", MediaType.APPLICATION_JSON));

    String response = dataApiClientImpl.getItem("asdf12345", "test-obj-id");
    Assertions.assertThat(response).isNotNull();
}

为什么queryParam()仍然有用

如果直接用完整URL带查询参数做匹配,会被查询参数的顺序、编码格式影响校验结果,比如参数顺序是keyid在前还是token在前就会导致匹配失败。而queryParam()会自动解析所有查询参数,不关心参数顺序,还可以单独校验每个参数的取值规则,比全URL匹配的灵活性和可读性高很多。

临时替代方案(不推荐)

如果不想自定义Matcher,也可以直接用Hamcrest的组合Matcher实现精确路径匹配,避免startsWith的模糊匹配问题:

mockRestServiceServer.expect(MockRestRequestMatchers.requestTo(
    CoreMatchers.allOf(
        CoreMatchers.startsWith(OBJECT_ID_URI),
        CoreMatchers.either(CoreMatchers.endsWith(OBJECT_ID_URI))
                .or(CoreMatchers.containsString(OBJECT_ID_URI + "?"))
    )
))

内容的提问来源于stack exchange,提问作者madhav-turangi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 23:36:04