Spock 和 Spring Boot 集成测试

Posted

技术标签:

【中文标题】Spock 和 Spring Boot 集成测试【英文标题】:Spock & Spring Boot Integration Test 【发布时间】:2017-06-28 09:07:58 【问题描述】:

我有一个使用 Spock 1.1 进行集成测试的 spring boot 1.5.1.RELEASE 项目。我有一个基本的控制器:

@RestController("/words")
public class WordsController 

   @RequestMapping(method = RequestMethod.GET)
   @ResponseBody
   public ResponseEntity getAllWords() 
      return ResponseEntity
         .status(HttpStatus.OK)
         .contentType(MediaType.APPLICATION_JSON)
         .body("Your list of words go here");
   

我正在尝试使用以下方法测试端点:

@ContextConfiguration(classes = MyApplication.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ActiveProfiles("test")
class WordsControllerTest extends Specification 
RESTClient restClient = new RESTClient("http://localhost:3000", ContentType.JSON)

    def "test the GET endpoint is available"() 
        when:
        def response = restClient.get(
                path: '/words',
                requestContentType: JSON
        )

        then:
        response.status == 200
    

这是我的应用程序主类:

@SpringBootApplication
public class MyApplication 

    public static void main(String[] args) 
        SpringApplication.run(MyApplication.class, args);
    


但是当我运行它时,我得到了一个非常奇怪的错误:

groovyx.net.http.RESTClient:解析错误 “应用程序/json”响应

groovy.json.JsonException: 无法确定当前字符, 它不是字符串、数字、数组或对象

当前读取的字符是 'Y',int 值为 89 无法 确定当前字符,它不是字符串、数字、数组或 对象行号 1 索引号 0 你的单词列表去 在这里………………………………………………………………………………………… ������������������������������������������������������ ������������������������������������������������������ ������������������������������������������������������ ������������������������������ ^ 在 groovy.json.internal.JsonParserCharArray.decodeValueInternal(JsonParserCharArray.java:206) ~[groovy-all-2.4.7.jar:2.4.7] 在 groovy.json.internal.JsonParserCharArray.decodeValue(JsonParserCharArray.java:157) ~[groovy-all-2.4.7.jar:2.4.7] 在 groovy.json.internal.JsonParserCharArray.decodeFromChars(JsonParserCharArray.java:46) ~[groovy-all-2.4.7.jar:2.4.7] 在 groovy.json.internal.JsonParserCharArray.parse(JsonParserCharArray.java:384) ~[groovy-all-2.4.7.jar:2.4.7] 在 groovy.json.internal.BaseJsonParser.parse(BaseJsonParser.java:128) ~[groovy-all-2.4.7.jar:2.4.7] 在 groovy.json.JsonSlurper.parse(JsonSlurper.java:221) ~[groovy-all-2.4.7.jar:2.4.7] 在 groovyx.net.http.ParserRegistry.parseJSON(ParserRegistry.java:280) ~[http-builder-0.7.1.jar:na] 在 sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法) ~[na:1.8.0_40] 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_40] 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_40] 在 java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_40] 在 org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93) ~[groovy-all-2.4.7.jar:2.4.7] 在 groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325) ~[groovy-all-2.4.7.jar:2.4.7] 在 groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1215) ~[groovy-all-2.4.7.jar:2.4.7] 在 groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1082) ~[groovy-all-2.4.7.jar:2.4.7] 在 groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024) ~[groovy-all-2.4.7.jar:2.4.7] 在 groovy.lang.Closure.call(Closure.java:414) ~[groovy-all-2.4.7.jar:2.4.7] 在 groovy.lang.Closure.call(Closure.java:430) ~[groovy-all-2.4.7.jar:2.4.7]

不确定它是否有所作为,但这是我的 gradle 文件的一部分:

compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-devtools')
compile("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
runtime('com.h2database:h2')
compile group: 'org.codehaus.groovy.modules.http-builder', name: 'http-builder', version: '0.7.1'
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('org.spockframework:spock-core:1.1-groovy-2.4-rc-2')
testCompile('org.spockframework:spock-spring:1.1-groovy-2.4-rc-2')
testCompile "org.hamcrest:hamcrest-core:1.2"

我不确定为什么没有正确发送或接收 JSON。

【问题讨论】:

【参考方案1】:

将端点标记为返回application/json 媒体类型是不够的。您还需要返回 有效 JSON 内容:

"Your list of words go here"

不是。

如果需要返回列表写:

return ResponseEntity
   .status(HttpStatus.OK)
   .contentType(MediaType.APPLICATION_JSON)
   .body("\"words\": [\"one\", \"two\"]");

或简单的消息:

return ResponseEntity
   .status(HttpStatus.OK)
   .contentType(MediaType.APPLICATION_JSON)
   .body("\"msg\": \"content\"");

Spring 可以自动将 POJO 映射到 JSON 负载,看看@ResponseBody

【讨论】:

谢谢,我知道@ResponseBody 会自动返回 JSON,但我错过了关于不返回实际有效 JSON 字符串的部分。

以上是关于Spock 和 Spring Boot 集成测试的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Spring Boot 应用程序和 Spock 测试在运行时更改服务器端口

在Spring Boot项目中使用Spock测试框架

使用带有 Spring Boot 的 Spock 测试框架来测试我的 REST 控制器

使用属性 server.port=0 运行 spock 测试时如何找到 Spring Boot 容器的端口

运行 Spring Boot 集成测试时出现 Liquibase 问题

如何使用 gradle 6+ 和 java 11+ 在 Spring Boot 中配置 spock