代码之家  ›  专栏  ›  技术社区  ›  deamon

测试中未找到带有Jersey的Spring Boot中的Handler方法

  •  2
  • deamon  · 技术社区  · 8 年前

    当应用程序启动并从测试访问时,Spring Boot/Jersey找不到处理程序方法。如果我单独启动应用程序并访问 http://localhost:8080/demo 有了浏览器一切都很好。

    日志显示:“找不到用于[/demo]的处理程序方法”。相关的日志输出:

    2018-06-18 17:04:31.071 DEBUG 7628 --- [nio-8080-exec-1] o.s.web.reactive.DispatcherHandler       : Processing GET request for [http://localhost:8080/demo]
    2018-06-18 17:04:31.083 DEBUG 7628 --- [nio-8080-exec-1] s.w.r.r.m.a.RequestMappingHandlerMapping : Looking up handler method for path /demo
    2018-06-18 17:04:31.085 DEBUG 7628 --- [nio-8080-exec-1] s.w.r.r.m.a.RequestMappingHandlerMapping : Did not find handler method for [/demo]
    2018-06-18 17:04:31.087 DEBUG 7628 --- [nio-8080-exec-1] o.s.w.r.handler.SimpleUrlHandlerMapping  : Matching pattern for request [[path='/demo']] is /**
    

    应用程序由以下类组成(用Kotlin编写):

    资源

    import org.springframework.stereotype.Component
    import javax.ws.rs.GET
    import javax.ws.rs.Path
    import javax.ws.rs.core.Response
    
    @Component
    @Path("/")
    class Resource {
    
        @GET
        @Path("demo")
        fun test() = Response.ok("Hi!").encoding("UTF-8").build()
    }
    

    运动衫配置

    import org.glassfish.jersey.server.ResourceConfig
    import org.springframework.stereotype.Component
    
    @Component
    class JerseyConfig : ResourceConfig() {
    
        init {
            register(Resource::class.java)
        }
    }
    

    应用程序:

    import org.springframework.boot.autoconfigure.SpringBootApplication
    import org.springframework.boot.runApplication
    
    @SpringBootApplication
    class App
    
    fun main(args: Array<String>) {
        runApplication<App>(*args)
    }
    

    失败的测试:

    import org.junit.jupiter.api.Test
    import org.junit.jupiter.api.TestInstance
    import org.junit.jupiter.api.extension.ExtendWith
    import org.springframework.beans.factory.annotation.Autowired
    import org.springframework.boot.test.context.SpringBootTest
    import org.springframework.test.context.junit.jupiter.SpringExtension
    import org.springframework.test.web.reactive.server.WebTestClient
    
    @ExtendWith(SpringExtension::class)
    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
    class ResourceTest {
    
        @Autowired
        lateinit var client: WebTestClient
    
        @Test
        fun getTest() {
            client.get().uri("demo").exchange().expectStatus().isOk
        }
    }
    

    如果我使用Jersey客户端进行测试,我也会遇到同样的错误:

    @Test
    fun testWithJersey() {
        val client = ClientBuilder.newClient()
        val response = client.target("http://localhost:8080/demo").request().get()
        assertThat(response.status).isEqualTo(200)
    }
    

    build.gradle公司:

    buildscript {
        ext {
            kotlinVersion = '1.2.50'
            springBootVersion = '2.0.3.RELEASE'
        }
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
            classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
            classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
        }
    }
    
    apply plugin: 'kotlin'
    apply plugin: 'kotlin-spring'
    apply plugin: 'org.springframework.boot'
    apply plugin: 'io.spring.dependency-management'
    
    compileKotlin {
        kotlinOptions {
            freeCompilerArgs = ["-Xjsr305=strict"]
            jvmTarget = "1.8"
        }
    }
    compileTestKotlin {
        kotlinOptions {
            freeCompilerArgs = ["-Xjsr305=strict"]
            jvmTarget = "1.8"
        }
    }
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
        compile("org.jetbrains.kotlin:kotlin-reflect")
        compile('org.springframework.boot:spring-boot-starter-jersey')
        testCompile("org.springframework.boot:spring-boot-starter-test") {
            exclude group: "junit", module: "junit"
        }
        testCompile('org.springframework.boot:spring-boot-starter-webflux')
        testCompile("org.junit.jupiter:junit-jupiter-api")
        testRuntime("org.junit.jupiter:junit-jupiter-engine")
    }
    

    测试代码本身似乎没问题,因为当我用 Thread.sleep(...) 然后从浏览器访问服务器,我得到同样的错误(404是由于“找不到用于[/demo]的处理程序方法”)。

    为什么在测试中找不到处理程序方法?我需要改变什么?

    2 回复  |  直到 8 年前
        1
  •  1
  •   Paul Samsotha    8 年前

    你确定吗? WebTestClient 是一个通用的客户机(它可以发出实际的网络请求),并且不仅仅意味着要与Spring MVC一起使用 MockMvc 是?这个错误听起来像是在寻找一个Spring MVC处理程序方法。如果它是一个通用客户机,则错误消息不会说明有关处理程序方法的任何内容,而可能会说明有关URL的内容。

    我想你需要用一个真正的客户机发出一个真正的网络请求。例如,如果你使用Jersey客户端,你可以做如下事情

    @LocalServerPort
    private int port;
    
    private Client client = ClientBuilder.newClient();
    
    @Test
    public void testCustomerLocationOnPost() {
        URI resourceUri = UriBuilder.fromUri("http://localhost")
                .port(port).path("demo").build();
    
        Respons response = client.target(resourcrUri).request().get();
    
        assertThat(response.getStatus()).isEqualTo(200);
    
    }
    
        2
  •  1
  •   deamon    8 年前

    在来自Pivotal的优秀人员的帮助下,我解决了这个问题: WebTestClient 需要 WebFlux 作为一种依赖。但是WebFlux不仅带来了一个小的测试助手,而且带来了一个成熟的web框架,它由Spring Boot自动配置,并且与Jersey冲突。

    解决办法是 移除WebFlux 从依赖关系

    dependencies {
        compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
        compile("org.jetbrains.kotlin:kotlin-reflect")
        compile('org.springframework.boot:spring-boot-starter-jersey')
        testCompile("org.springframework.boot:spring-boot-starter-test") {
            exclude group: "junit", module: "junit"
        }
        testCompile("org.junit.jupiter:junit-jupiter-api")
        testRuntime("org.junit.jupiter:junit-jupiter-engine")
    }
    

    并使用,例如,Jersey http客户端:

    @ExtendWith(SpringExtension::class)
    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
    class ResourceTest {
    
        @Test
        fun testWithJerseyClient() {
            val client = ClientBuilder.newClient()
            val response = client.target("http://localhost:8080/demo").request().get()
            assertThat(response.status).isEqualTo(200)
        }
    }
    

    但只要WebFlux不是依赖项,任何其他http客户端都可以。

    更新: 这是弹簧靴的一个漏洞 固定在弹簧套2.0.4中 ! 然后您可以使用WebFlux和服务器端的Jersey一起进行测试。