今天主要是梳理springboot单元测试,基于MockMvc进行实战演示。
springboot本身就集成并且提供了非常多的实用工具以及注解。帮助开发者更加专注业务开发。
在这里主要介绍一下,springboot提供的测试方面的工具以及注解。主要包括两个模块:
spring-boot-test: 支持测试的核心内容。
spring-boot-test-autoconfigure:支持测试的自动化配置
我们只需要引入上面的依赖,springboot就会帮我们引入测试模块。我们只需要使用注解。就能轻松完成调用。
比如引入的测试类库有:
@BeforeClass: 针对所有的测试,只执行一次,且方法还必须是static void
@Before: 初始化方法,执行当前测试类的每个测试方法前执行
@Test: 测试方法,在这里执行测试,也可以测试期望异常和超时时间(可以查看注解源码,查看使用属性)
@After: 释放资源,可以执行当前测试类的每一个测试方法后执行
@AfterClass: 针对所有的测试,只执行一次,且方法还必须是static void
@Ignore: 忽略此测试方法
@Runwith: 可以更改测试运行器
一个单元测试类执行的顺序:
@BeforeClass
-> @Before
-> @Test
-> @After
-> @AfterClass
每个一个测试方法执行的调用顺序:
@Before
-> @Test
-> @After
在JUnit中有很多个Runner,他们负责调用你的测试代码,每一个Runner都有各自的特殊功能,你要根据需要选择不同的Runner来运行你的测试代码。在测试的时候,不指定使用的是默认的Runner。只能测试普通的java测试。不涉及spring web
项目
在springboot中,SpringBoot 2.X 默认使用Junit4 我们使用注解@RunWith(SpringRunner.class)
进行指定
public final class SpringRunner extends SpringJUnit4ClassRunner {
public SpringRunner(Class<?> clazz) throws InitializationError {
super(clazz);
}
}
可以看到源码中,SpringRunner
继承的SpringJUnit4ClassRunner
@SpringBootTest注解是SpringBoot自1.4.0版本开始引入的一个用于测试的注解。他是属于SpringBoot的注解。
在进行web 环境测试的时候,我通常使用@SpringBootTest(classes = SpringbootApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
其中classes = SpringbootApplication.class
是指定启动类、webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
是指定web环境
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@BootstrapWith(SpringBootTestContextBootstrapper.class)
public @interface SpringBootTest {
@AliasFor("properties")
String[] value() default {};
@AliasFor("value")
String[] properties() default {};
Class<?>[] classes() default {};
WebEnvironment webEnvironment() default WebEnvironment.MOCK;
enum WebEnvironment {
MOCK(false),
RANDOM_PORT(true),
DEFINED_PORT(true),
NONE(false);
private final boolean embedded;
WebEnvironment(boolean embedded) {
this.embedded = embedded;
}
public boolean isEmbedded() {
return this.embedded;
}
}
}
查看源码发现:
SpringBootTest.WebEnvironment
中一共有 4 个枚举值
还有不少人的文章说,SpringBootTest.WebEnvironment.RANDOM_PORT 必须或通常和 @LocalServerPort 一起使用。我看源码的注释,解释并没有说跟@LocalServerPort 一起使用。我本身也不用。
为了减少篇幅,文中源码注释我都做了删除处理。感兴趣可以自己去查看。
MockMvc是由spring-test包提供,实现了对Http请求的模拟,能够直接使用网络的形势,转换到Controller的调用,是的测试速度快,不依赖网络环境。同时提供了一套验证的工具,结果的验证十分方便。
基于RESTful 风格的springMVC测试。可以测试整个SpringMVC流程。从URL请求到Controller控制层的测试。
MockMVCBuilders
的静态方法建造MockMVCBuilder
,MockMvc
由MockMVCBuilder
构造方法介绍:
完整的代码github路径: [email protected]:agreewangshuai/marsha_springboot.git
(一个完整的springboot骨架集成统一结果返回、统一异常处理、统一日志框架以及单元测试、swagger)
添加Gradle依赖
testImplementation('org.springframework.boot:spring-boot-starter-test')
model
@ApiModel(value = "HelloWorld参数类")
public class HelloWorld {
@ApiModelProperty(value = "要说内容")
@NotNull(message = "不能为空或者\"\"")
private String say;
public String getSay() {
return say;
}
public void setSay(String say) {
this.say = say;
}
}
controller
@RestController
@RequestMapping("/agree")
@Api(value = "类描述",tags = {"hello demo功能"})
public class HelloWorldController {
@Autowired
HelloWorldService helloWorldService;
@ApiOperation(value = "返回say hello",notes = "方法的具体描述信息")
@GetMapping("/helloworld")
public ResponseData getHello(@RequestBody @Valid HelloWorld helloWorld) {
String say = helloWorld.getSay();
String sayhello = helloWorldService.sayhello(say);
return new ResponseData().ok().data(sayhello);
}
}
service
public interface HelloWorldService {
/**
* @param say
* @return
*/
String sayhello(String say);
}
serviceImpl
@Service
public class HelloWorldServiceImpl implements HelloWorldService{
@Override
public String sayhello(String say) {
return say;
}
}
Test
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HelloWorldControllerTest {
public static final Logger log = LoggerFactory.getLogger(HelloWorldControllerTest.class);
@Autowired
private WebApplicationContext ctx;
private MockMvc mvc;
@Before
public void before() {
mvc = MockMvcBuilders.webAppContextSetup(ctx).build();
}
@Test
public void getHelloTest() throws Exception {
RequestBuilder request = null;
MvcResult mvcResult = null;
HelloWorld helloWorld = new HelloWorld();
// helloWorld.setSay("say agree");
/**
* 添加请求参数,此处示例传参格式为json
* new JsonHelper().objectToJson(helloWorld)是我自己写的一个util类,将model转为json
* 嫌麻烦也可以直接写成json格式:
* content("{\"say\":\"hello world\"}")
*/
request = MockMvcRequestBuilders.get("/agree/helloworld").content(new JsonHelper().objectToJson(helloWorld))
.contentType(MediaType.APPLICATION_JSON);
mvcResult = mvc.perform(request).andExpect(status().isOk()).andReturn();
// 获取数据
JSONObject jsonObject = new JSONObject(mvcResult.getResponse().getContentAsString());
log.info("输出返回结果:{}", jsonObject);
// 加断言,判断属性值的问题。
Assert.assertNotNull(jsonObject.get("code"));
Assert.assertEquals(jsonObject.get("code"), "0");
Assert.assertNotNull(jsonObject.get("message"));
Assert.assertEquals(jsonObject.get("message"), "操作成功");
Assert.assertNotNull(jsonObject.get("data"));
}
}
本文单元测试主要描述了springboot单元测试的MockMvc。主要针对controller层的单元测试方法的介绍。目前暂时用的功能就这么多。后续有新的研究心得,会持续更新。如有纰漏,欢迎指正。谢谢