Spring入门(十四):Spring MVC控制器的2种测试方法
作为一名研发人员,不管你愿不愿意对自己的代码进行测试,都得承认测试对于研发质量保证的重要性,这也就是为什么每个公司的技术部都需要质量控制部的原因,因为越早的发现代码的bug,成本越低,比如说,dev环境发现bug的成本要低于qa环境,qa环境发现bug的成本要低于prod环境,prod环境发现bug的成本最高,这也是每个研发人员最不愿意遇到但永远避不掉的现实。
虽然不能完全避免,但我们可以对自己的代码进行充分的测试,降低bug出现的几率。
所以, 本篇博客我们主要讲解下spring mvc控制器的3种测试方法:
- 部署项目后测试
- 借助junit和spring test框架测试
- 借助swaggerui接口文档测试
1. 部署项目后测试
在前2篇博客中,我们采取的就是这种测试方式,即将项目打成war包,部署到tomcat中,运行项目后, 借助浏览器或者postman等工具对控制器进行测试。
如果是get请求,可以使用浏览器或者postman测试。
如果是post、put、delete等请求,可以使用postman进行测试。
有兴趣的同学,可以看下之前的2篇博客:
2. 借助junit和spring test框架测试
上面的方法虽然可以进行测试,但每次都打包、部署、运行项目、测试,显然很不方便,不过强大的spring通过spring test框架对集成测试提供了支持,接下来我们讲解具体的使用方法。
因为我们的spring项目是通过maven管理的,所以它的项目结构有以下4个目录:
- src/main/java:项目代码
- src/main/resources:项目资源
- src/test/java:测试代码
- src/test/resources:测试资源(该目录默认没有生成,有需要的可以自己新建)
也就是说,我们可以将我们的测试代码放在src/test/java目录下,不过截止目前,我们还并未在该目录添加任何测试代码。
2.1 添加依赖
在添加测试代码前,我们需要在pom.xml中添加如下依赖:
<dependency> <groupid>org.springframework</groupid> <artifactid>spring-test</artifactid> <version>4.3.18.release</version> <scope>test</scope> </dependency> <dependency> <groupid>junit</groupid> <artifactid>junit</artifactid> <version>4.12</version> <scope>test</scope> </dependency>
也许有的同学会好奇,为啥本次添加的依赖增加了<scope>test</scope>
, 它有啥作用呢?
带着这个疑问,我们编译下项目,发现原本编译正常的代码竟然编译报错了:
报错信息提示程序包org.junit不存在,可我们明明添加了该依赖啊,这是为什么呢,会不会和<scope>test</scope>
有关呢?
恭喜你,猜对了,确实和<scope>test</scope>
有关,如果你此时将该项移除,项目编译就不报错了(不过建议不要移除)。
这是因为,我们在之前添加测试代码时,都是放在src/main/java目录下的,现在依赖包增加了<scope>test</scope>
,说明这些包的存活周期是在test周期,所以我们可以把之前的测试代码移到src/test/java目录下,如下所示:
再次编译项目,发现编译通过。
2.2 添加控制器
添加控制器前,新建demoservice如下所示:
package chapter05.service; import org.springframework.stereotype.service; @service public class demoservice { public string saysomething() { return "hello"; } }
注意事项:该类添加了@service注解。
然后,新建控制器normalcontroller,它里面的方法返回jsp视图:
package chapter05.controller; import chapter05.service.demoservice; import org.springframework.beans.factory.annotation.autowired; import org.springframework.stereotype.controller; import org.springframework.ui.model; import org.springframework.web.bind.annotation.requestmapping; @controller public class normalcontroller { @autowired private demoservice demoservice; @requestmapping("/normal") public string testpage(model model) { model.addattribute("msg", demoservice.saysomething()); return "page"; } }
接着新建控制器myrestcontroller,它里面的方法直接返回信息:
package chapter05.controller; import chapter05.service.demoservice; import org.springframework.beans.factory.annotation.autowired; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.restcontroller; @restcontroller public class myrestcontroller { @autowired private demoservice demoservice; @requestmapping(value = "/testrest", produces = "text/plain;charset=utf-8") public string testrest() { return demoservice.saysomething(); } }
2.3 添加测试代码
在src/test/java下新建包chapter05,然后在其下面新建测试类testcontrollerintegrationtests如下所示:
package chapter05; import chapter05.config.mymvcconfig; import chapter05.service.demoservice; import org.junit.before; import org.junit.runner.runwith; import org.springframework.beans.factory.annotation.autowired; import org.springframework.test.context.contextconfiguration; import org.springframework.test.context.junit4.springjunit4classrunner; import org.springframework.test.context.web.webappconfiguration; import org.springframework.test.web.servlet.mockmvc; import org.springframework.test.web.servlet.setup.mockmvcbuilders; import org.springframework.web.context.webapplicationcontext; @runwith(springjunit4classrunner.class) @contextconfiguration(classes = {mymvcconfig.class}) @webappconfiguration("src/main/resources") public class testcontrollerintegrationtests { private mockmvc mockmvc; @autowired private demoservice demoservice; @autowired private webapplicationcontext webapplicationcontext; @before public void setup() { this.mockmvc = mockmvcbuilders.webappcontextsetup(this.webapplicationcontext).build(); } }
代码讲解:
@runwith(springjunit4classrunner.class)
用于在junit环境下提供spring test框架的功能。
@contextconfiguration(classes = {mymvcconfig.class})
用来加载配置applicationcontext,其中classes属性用来加载配置类,mymvcconfig配置类的代码如下所示:
package chapter05.config; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.componentscan; import org.springframework.context.annotation.configuration; import org.springframework.web.servlet.config.annotation.enablewebmvc; import org.springframework.web.servlet.view.internalresourceviewresolver; import org.springframework.web.servlet.view.jstlview; /** * spring mvc配置 */ @configuration @enablewebmvc @componentscan("chapter05") public class mymvcconfig { /** * 视图解析器配置 * * @return */ @bean public internalresourceviewresolver viewresolver() { internalresourceviewresolver viewresolver = new internalresourceviewresolver(); viewresolver.setprefix("/web-inf/classes/views/"); viewresolver.setsuffix(".jsp"); viewresolver.setviewclass(jstlview.class); return viewresolver; } }
@webappconfiguration("src/main/resources")
用来声明加载的applicationcontext是一个webapplicationcontext,它的属性指定的是web资源的位置,默认为src/main/webapp,这里我们修改成
src/main/resources。
mockmvc用来模拟mvc对象,它在添加了@before
注解的setup()中,通过this.mockmvc = mockmvcbuilders.webappcontextsetup(this.webapplicationcontext).build();
进行初始化赋值。
然后往测试类中添加如下测试代码:
@test public void testnormalcontroller() throws exception { mockmvc.perform(get("/normal")) .andexpect(status().isok()) .andexpect(view().name("page")) .andexpect(forwardedurl("/web-inf/classes/views/page.jsp")) .andexpect(model().attribute("msg", demoservice.saysomething())); }
代码解释:
perform(get("/normal"))
用来模拟向/normal发起get请求,
andexpect(status().isok())
预期返回的状态码为200,
andexpect(view().name("page"))
预期视图的逻辑名称为page,
andexpect(forwardedurl("/web-inf/classes/views/page.jsp"))
预期视图的真正路径是/web-inf/classes/views/page.jsp",
andexpect(model().attribute("msg", demoservice.saysomething()))
预期model里有一个msg属性,它的值是demoservice.saysomething()
的返回值hello。
执行该测试方法,测试通过:
最后往测试类中添加如下测试代码:
@test public void testrestcontroller() throws exception { mockmvc.perform(get("/testrest")) .andexpect(status().isok()) .andexpect(content().contenttype("text/plain;charset=utf-8")) .andexpect(content().string(demoservice.saysomething())); }
代码解释:
perform(get("/testrest"))
用来模拟向/testrest发起get请求,
andexpect(status().isok())
预期返回的状态码为200,
andexpect(content().contenttype("text/plain;charset=utf-8"))
预期返回值的媒体类型为text/plain;charset=utf-8,
andexpect(content().string(demoservice.saysomething()))
预期返回值的内容为demoservice.saysomething()
的返回值hello。
执行该测试方法,测试通过:
3. 源码及参考
源码地址:,欢迎下载。
craig walls 《spring实战(第4版)》
汪云飞《java ee开发的颠覆者:spring boot实战》
4. 最后
欢迎扫码关注微信公众号:「申城异乡人」,定期分享java技术干货,让我们一起进步。
上一篇: BIO、NIO、AIO
下一篇: 学习python (1)