如何修复使用JAX-RS/Jersey的Spring Boot应用测试失败问题
问题:Spring Boot中JAX-RS/Jersey端点的测试修复方案
基于Spring Boot的Web层测试场景,初始使用Spring MVC控制器时,标注@SpringBootTest的测试可正常通过;但将应用重构为JAX-RS/Jersey端点替代控制器后,测试失败,需修复该测试。
场景1:使用Spring MVC控制器的正常测试
控制器代码
package org.example; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public final class GreetingController { @GetMapping("/") public @ResponseBody String helloWorld() { return "Hello, world!"; } }
应用启动类
package org.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class GreetingApplication { public static void main(String[] args) { SpringApplication.run(GreetingApplication.class, args); } }
测试类(可正常通过)
package org.example; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.web.servlet.MockMvc; @SpringBootTest @AutoConfigureMockMvc public final class GreetingApplicationTest { @Autowired private MockMvc mvc; @Test public void helloWorld() throws Exception { mvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("Hello, world!")); } }
表现:运行应用手动测试正常,执行./gradlew build测试通过。
场景2:切换为JAX-RS/Jersey端点后测试失败
修改内容
- 删除
GreetingController - 新增
GreetingEndpoint - 新增
JerseyConfig
新增的端点代码
package org.example; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import org.springframework.stereotype.Component; @Component @Path("/") public final class GreetingEndpoint { @GET public String helloWorld() { return "Hello, world!"; } }
Jersey配置类
package org.example; import org.glassfish.jersey.server.ResourceConfig; import org.springframework.stereotype.Component; @Component public final class JerseyConfig extends ResourceConfig { public JerseyConfig() { register(GreetingEndpoint.class); } }
表现:运行应用手动测试正常,但执行./gradlew build时测试失败。
修复方案
核心原因:MockMvc是Spring MVC专属测试工具,无法直接处理Jersey端点请求。以下两种方案可解决问题:
方案1:使用Jersey原生测试框架
步骤1:添加Jersey测试依赖
在build.gradle.kts的dependencies块中加入:
testImplementation("org.glassfish.jersey.test-framework.providers:jersey-test-framework-provider-grizzly2:3.1.5")
步骤2:修改测试类
package org.example; import jakarta.ws.rs.core.MediaType; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; public class GreetingEndpointTest extends JerseyTest { @Override protected ResourceConfig configure() { return new JerseyConfig(); } @Test public void helloWorld() { String response = target("/") .request(MediaType.TEXT_PLAIN) .get(String.class); assertEquals("Hello, world!", response); } }
优势:无需启动完整Spring上下文,测试速度更快。
方案2:使用Spring Boot的TestRestTemplate
利用TestRestTemplate启动真实Servlet容器,可处理Jersey端点请求:
package org.example; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; import static org.junit.jupiter.api.Assertions.assertEquals; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class GreetingEndpointTest { @Autowired private TestRestTemplate restTemplate; @Test public void helloWorld() { String response = restTemplate.getForObject("/", String.class); assertEquals("Hello, world!", response); } }
优势:依赖完整Spring上下文,更贴近真实运行环境,适合需要Spring Bean注入的场景。
完整build.gradle.kts配置
plugins { java id("org.springframework.boot") version "3.4.0" } repositories { mavenCentral() } dependencies { implementation("jakarta.ws.rs:jakarta.ws.rs-api:4.0.0") implementation("org.springframework.boot:spring-boot-starter-jersey:3.4.0") implementation("org.springframework.boot:spring-boot-starter-web:3.4.0") testImplementation("org.junit.jupiter:junit-jupiter-api:5.11.3") testImplementation("org.springframework.boot:spring-boot-starter-test:3.4.0") // 方案1需要的Jersey测试依赖,方案2可注释 testImplementation("org.glassfish.jersey.test-framework.providers:jersey-test-framework-provider-grizzly2:3.1.5") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.11.3") testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.11.3") } java { toolchain { languageVersion = JavaLanguageVersion.of(21) } } tasks.named<Test>("test") { useJUnitPlatform() }
内容的提问来源于stack exchange,提问作者MikeW
相关产品推荐
相关产品推荐

