1. springboot2.X 集成 spock-spring 进行单元测试,在 pom 中添加 spock 依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.spockframework/spock-spring --> <dependency> <groupId>org.spockframework</groupId> <artifactId>spock-spring</artifactId> <version>1.3-groovy-2.5</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.spockframework/spock-core --> <dependency> <groupId>org.spockframework</groupId> <artifactId>spock-core</artifactId> <version>1.3-groovy-2.5</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-all --> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>2.5.8</version> <type>pom</type> <scope>test</scope> </dependency>
添加两个plugin用于编译 groovy 代码和使用spock测试的类名规则
<!-- Mandatory plugins for using Spock --> <plugin> <!-- The gmavenplus plugin is used to compile Groovy code. To learn more about this plugin, visit https://github.com/groovy/GMavenPlus/wiki --> <groupId>org.codehaus.gmavenplus</groupId> <artifactId>gmavenplus-plugin</artifactId> <version>1.11.0</version> <executions> <execution> <goals> <goal>compile</goal> <goal>compileTests</goal> </goals> </execution> </executions> </plugin>
2 在项目中新加如下测试目录结构
标记 groovy 目录为 test source root
3 spock 中的代码块和junit对应关系
4 常用的模式有
初始化/执行/期望 given: when: then: 期望/数据表 expect: where:
4.1 数据表中每个测试都是相互独立的,都是specification class该类型的一个具体实例,每条都会执行 setup() cleanup()方法,
4.2 常用的指令有
@Shared //共享 @Timeout //超时时间 @Ignore //忽略该方法 @IgnoreRest //忽略其他方法 @FailsWith //有些问题暂时没有解决
@Unroll
// 每个循环独立报告
5 测试 json 请求
//controller 方法 @Slf4j @RestController public class StudentController { @RequestMapping(path = "/student", method = RequestMethod.POST) public Student addStudent(@RequestBody Student student) { if (student.getName() == null) { throw new RuntimeException("name is null"); } log.info("request msg:[{}]", student); Random random = new Random(); student.setId(random.nextInt(1000)); log.info("response msg:[{}]", student); return student; } } //Student model @Data @Builder @AllArgsConstructor @NoArgsConstructor public class Student { private Integer id; private String name; private Integer age; }
编写单元测试方法
package com.huitong.controller import com.huitong.model.Student import com.huitong.util.JsonObjectUtil 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.http.MediaType import org.springframework.test.context.ActiveProfiles import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import spock.lang.Specification import javax.servlet.http.HttpServletResponse /** * <p> * </p> * author pczhao <br/> * date 2020/11/15 11:39 */ @ActiveProfiles("dev") @SpringBootTest @AutoConfigureMockMvc class StudentControllerTest extends Specification { @Autowired private MockMvc mockMvc; def "this is my first web test"() { given: def stu = Student.builder().name("allen").age(23).build(); when: def res = mockMvc.perform( MockMvcRequestBuilders.post("/student") .contentType(MediaType.APPLICATION_JSON).content(JsonObjectUtil.convertObjectToJson(stu))) .andReturn() then: res.response.status == HttpServletResponse.SC_OK } }
6 测试文件上传
//controller 文件 @Slf4j @RestController public class FileController { @RequestMapping(path = "/upload/file", method = RequestMethod.POST) public String uploadFile(@RequestParam("username") String username, @RequestParam("file") MultipartFile file) { String desDir = "D:\logs\service-demo\"; String desFilename = desDir + file.getOriginalFilename(); try { file.transferTo(new File(desFilename)); return username + " upload file success, " + desFilename; } catch (IOException e) { log.error(e.getMessage(), e); } return username + " upload file failure, " + desFilename; } }
对应的groovy测试文件
package com.huitong.controller import org.apache.commons.io.FileUtils 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.mock.web.MockMultipartFile import org.springframework.test.context.ActiveProfiles import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder import spock.lang.Specification import javax.servlet.http.HttpServletResponse /** * <p> * </p> * author pczhao <br/> * date 2020/11/15 13:48 */ @ActiveProfiles("dev") @SpringBootTest @AutoConfigureMockMvc class FileControllerTest extends Specification { @Autowired private MockMvc mockMvc; def "test upload file controller"() { given: String username = "allen" MockMultipartFile srcFile = new MockMultipartFile("file", "test.pptx", "text/plain", FileUtils.readFileToByteArray(new File("C:\Users\Administrator.DESKTOP-D5RT07E\Desktop\test.pptx"))) when: def result = mockMvc.perform(new MockMultipartHttpServletRequestBuilder("/upload/file").file(srcFile).param("username", username)).andReturn() println(result) then: result.response.status == HttpServletResponse.SC_OK } }
参考资料:
http://spockframework.org/spock/docs/1.3/all_in_one.html#_using_code_with_code_for_expectations