Java 使用gradle为spring boot REST服务运行集成测试

Java 使用gradle为spring boot REST服务运行集成测试,java,gradle,spring-boot,integration-testing,Java,Gradle,Spring Boot,Integration Testing,我目前正在尝试为REST服务设置集成测试框架,该服务基于: 弹簧靴 格拉德尔 码头 我能够使用spring boot集成测试框架以及spring boot junit runner打开应用程序上下文并成功运行测试 接下来我要做的是做一个渐变任务,它将完成以下任务: 构建jar(而不是war) 启动jetty并部署jar 对这个jar运行一组测试用例 停靠码头 =>我尝试使用“jetty”插件。但它似乎不支持jar文件。 =>然后我尝试使用JavaExec任务运行jar,然后运行测试,但是在测试完

我目前正在尝试为REST服务设置集成测试框架,该服务基于:

  • 弹簧靴
  • 格拉德尔
  • 码头
  • 我能够使用spring boot集成测试框架以及spring boot junit runner打开应用程序上下文并成功运行测试

    接下来我要做的是做一个渐变任务,它将完成以下任务:

  • 构建jar(而不是war)
  • 启动jetty并部署jar
  • 对这个jar运行一组测试用例
  • 停靠码头
  • =>我尝试使用“jetty”插件。但它似乎不支持jar文件。
    =>然后我尝试使用JavaExec任务运行jar,然后运行测试,但是在测试完成后,我找不到一种直接的方法来停止jar进程
    =>Exec类型任务也存在同样的问题

    因此,我有两个问题:

  • 是否有一种方法可以使用gradle实现上述形式的集成测试

  • 这是推荐的集成测试方法还是有更好的方法

  • 非常感谢您的任何想法和见解


    谢谢,

    有不同的方法来实现你想要的。我在客户端帮助的方法依赖于Spring Boot Actuator提供的/shutdown URL重要如果使用此方法,请确保在生产过程中使用这两种方法之一

    在生成文件中,您有两个任务:

    task startWebApp(type: StartApp) {
        dependsOn 'assemble'
        jarFile = jar.archivePath
        port = 8080
        appContext = "MyApp"
    }
    
    task stopWebApp(type: StopApp) {
        urlPath = "${startWebApp.baseUrl}/shutdown"
    }
    
    您应该确保您的集成测试依赖于
    startWebApp
    任务,并且它们应该由stop任务完成。比如说:

    integTest.dependsOn "startWebApp"
    integTest.finalizedBy "stopWebApp"
    
    当然,您还需要创建自定义任务实现:

    class StartApp extends DefaultTask {
        static enum Status { UP, DOWN, TIMED_OUT }
    
        @InputFile
        File jarFile
    
        @Input
        int port = 8080
    
        @Input
        String appContext = ""
    
        String getBaseUrl() {
            return "http://localhost:${port}" + (appContext ? '/' + appContext : '')
        }
    
        @TaskAction
        def startApp() {
            logger.info "Starting server"
            logger.debug "Application jar file: " + jarFile
    
            def args = ["java",
                    "-Dspring.profiles.active=dev",
                    "-jar",
                    jarFile.path]
            def pb = new ProcessBuilder(args)
            pb.redirectErrorStream(true)
    
            final process = pb.start()
            final output = new StringBuffer()
            process.consumeProcessOutputStream(output)
    
            def status = Status.TIMED_OUT
            for (i in 0..20) {
                Thread.sleep(3000)
    
                if (hasServerExited(process)) {
                    status = Status.DOWN
                    break
                }
    
                try {
                    status = checkServerStatus()
                    break
                }
                catch (ex) {
                    logger.debug "Error accessing app health URL: " + ex.message
                }
            }
    
            if (status == Status.TIMED_OUT) process.destroy()
    
            if (status != Status.UP) {
                logger.info "Server output"
                logger.info "-------------"
                logger.info output.toString()
                throw new RuntimeException("Server failed to start up. Status: ${status}")
            }
        }
    
        protected Status checkServerStatus() {
            URL url = new URL("$baseUrl/health")
            logger.info("Health Check --> ${url}")
            HttpURLConnection connection = url.openConnection()
            connection.readTimeout = 300
    
            def obj = new JsonSlurper().parse(
                connection.inputStream,
                connection.contentEncoding ?: "UTF-8")
            connection.inputStream.close()
            return obj.status == "UP" ? Status.UP : Status.DOWN
        }
    
        protected boolean hasServerExited(Process process) {
            try {
                process.exitValue()
                return true
            } catch (IllegalThreadStateException ex) {
                return false
            }
        }
    }
    
    请注意,在线程上启动服务器很重要,否则任务永远不会结束。停止服务器的任务更简单:

    class StopApp extends DefaultTask {
    
        @Input
        String urlPath
    
        @TaskAction
        def stopApp(){
            def url = new URL(urlPath)
            def connection = url.openConnection()
            connection.requestMethod = "POST"
            connection.doOutput = true
            connection.outputStream.close()
            connection.inputStream.close()
        }
    }
    
    它基本上会向/shutdown URL发送一个空POST,以停止正在运行的服务器