技术标签: springboot 单测加入参数
(当接口的参数用@RequestBody修饰,同时还有另外的参数的情况)
测试接口的时候,如果项目中请求经过网关,转发到服务时,中间会将请求头数据转换成参数对象Subject。
格式如下:
@PutMapping("/demo/update")public String update(@Valid @RequestBody DemoRO demoRO, Subject subject) {
//...
return "success";
}
这时,如果使用mock测试,参数subject传递一直失败,无法解析。
经过一番查找,将实现了解析参数的 WebMvcConfigurer的实现类WebConfiguration加到Test的基类中加载,实现了正常的接口测试
@Configurationpublic class WebConfiguration implementsWebMvcConfigurer {publicWebConfiguration() {
}//...
@Beanpublic FilterRegistrationBeanglobalContextFilter() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean(new GlobalContextFilter(), new ServletRegistrationBean[0]);
registrationBean.addUrlPatterns(new String[]{"/*"});
registrationBean.setOrder(-2147483548);returnregistrationBean;
}public void addArgumentResolvers(Listresolvers) {//根据函数定义的参数类型匹配传入的参数,并转换成Subject对象
resolvers.add(newSubjectHandlerMethodArgumentResolver());
}//...
}
请求参数与接口参数匹配类
public class SubjectHandlerMethodArgumentResolver implementsHandlerMethodArgumentResolver {publicSubjectHandlerMethodArgumentResolver() {
}public booleansupportsParameter(MethodParameter parameter) {return Subject.class.isAssignableFrom(parameter.getParameterType());
}public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throwsException {
//如果接口参数满足类型匹配(即 supportsParameter == true),则获取由GlobalContext管理的存储在ThreadLocal的subjectreturn GlobalContext.getSubject().orElse((Object)null);
}}
请求拦截器GlobalContextFilter
public class GlobalContextFilter extendsOncePerRequestFilter {publicGlobalContextFilter() {
}protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throwsServletException, IOException {this.resolverSubject(request);try{
filterChain.doFilter(request, response);
}finally{this.clear();
}
}private voidclear() {
GlobalContext.clear();
}//...
private voidresolverSubject(HttpServletRequest request) {if (NumberUtils.isNumber(request.getHeader("user-Id"))) {
Long id= Long.valueOf(request.getHeader("user-Id"));
Subject subject=Subject.builder().id(id).build();//解析请求头,并存入封装了ThreadLocal的GlobalContext中
GlobalContext.setSubject(subject);
}
}
}
测试基类
@RunWith(SpringRunner.class)
@SpringBootTest(classes= DemoApplication.class, webEnvironment =SpringBootTest.WebEnvironment.DEFINED_PORT)
@ContextConfiguration(classes= WebConfiguration.class, initializers= ConfigFileApplicationContextInitializer.class)
@AutoConfigureMockMvcpublic classBaseTest {
@AutowiredprotectedMockMvc mockMvc;/*** web项目上下文*/@ResourceprivateWebApplicationContext webApplicationContext;
@Resourceprivate FilterRegistrationBeanglobalContextFilter;@Beforepublic voidbefore() {//获取mockmvc对象实例
mockMvc =MockMvcBuilders.webAppContextSetup(webApplicationContext)
.addFilter(globalContextFilter.getFilter())
.build();
}
}
Controller测试类
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
public class DemoControllerTest extendsBaseTest {private final HttpHeaders httpHeaders = newHttpHeaders();
@Overridepublic voidbefore() {super.before();httpHeaders.add("user-Id", "100001");
}
@Testpublic void testUpdate() throwsException {
DemoRO updateRO= newDemoRO();updateRO.setName("Demo111");this.mockMvc.perform(
put("/demo/update")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.headers(httpHeaders)
.content(JSON.toJSONString(updateRO))
).andDo(print());
}
文章浏览阅读1.5k次。 可能是汇编和组成原理都没有学透吧!@那个保护模式的确不太好理解.什么是保护模式 自从1969年推出第一个微处理器以来,Intel处理器就在不断地更新换代,从8086、8088、80286,到80386、80486、奔腾、奔腾Ⅱ、奔腾4等,其体系结构也在不断变化。80386以后,提供了一些新的功能,弥补了8086的一些缺陷。这其中包括内存保护、多任务及使用640KB以上的内存等,并仍然_保护模式 ds
文章浏览阅读3.5k次,点赞5次,收藏2次。使用idea Debug启动项目10分钟都没启动好项目,但使用run可正常启动,解决方法如下:1、现象:idea debug启动后,卡在如下界面上。2、解决办法如下:经排查,发现是某个方式打了断点,把该断点去掉即可。控制台也有相应的提示。使用ctrl + shift + F8 可打开断点管理界面,把断点全部放开后,则debug启动项目正常,待Debug启动成功后再打上断点。断点管理界面如下,把所有断点的勾选去掉。..._idea debug运行米反应
文章浏览阅读5.2k次。Excel数据分析小技巧,让你快速了解并掌握散点图/气泡图~更有免费实战案例数据供你练习!!!_散点图数据实例
文章浏览阅读87次。Linux有四种基本文件系统类型:--普通文件:如文本文件、C语言源代码、shell脚本等,可以用cat、less、more、vi等来察看内容,用mv来改名;--目录文件:包括文件名、子目录名及其指针,可以用ls列出目录文件;--链接文件:是指向一索引节点的那些目录条目,用ls来查看时,链接文件的标志用l开头,而文件后以"->"指向所链接的文件;--特殊文件:如磁盘、终..._linux 5.4.0版本ip地址文件夹
文章浏览阅读2.9k次,点赞6次,收藏37次。在开发一款背单词的微信小程序时,为了加强用户的体验感,刺激用户积极学习,小程序中需要有的模块。通过打卡天数来排名,让用户有攀比学习的心里。_小程序 排行榜素材
文章浏览阅读1.6k次。1、MessageBox 弹框在做项目的过程中遇到了这样一种情况文字需要换行处理。但是删除一般都用这个,非常的方便且契合,但是对于提示的内容,我试了在字符串里添加 \n 和 \r\n 都没有换行的效果,本来想换一个方法实现,但是不知道为啥,忽然那股觉得一定有解决方法的劲儿又上来了,果然,被我找到了解决方法,感谢这篇博客呀~【element-ui】messageBox弹窗提示消息换行问题..._element upload给出弹窗提示后上传有问题
文章浏览阅读1.3k次,点赞4次,收藏14次。传送门:本文完整代码地址 如果觉得有帮助,别忘了点亮 star 哦 说明:本文为 Vue 2.x + Echarts 5.x 实现中国地图多级钻取功能(基本版 未做过多功能拓展和样式优化 便于二次开发)。由于祖国地大物博、地市众多,仅完成了省级行政区及部分地市的钻取,暂无地图数据的区域 大家可以自行移步 datav 地图选择器 下载相应的地图 json 数据,参照已有地市的配置实现即可。坐标拾取器:百度地图坐标拾取器案例效果..._echarts钻取下一层
文章浏览阅读2.7k次。Django中post与get的区别记录下Django中post与get的区别1.post是取页面中提交的值2.get是从数据库中取值_python request与get区别
文章浏览阅读6k次,点赞28次,收藏151次。这个东东第一次才开始写的时候,脑子都是懵的,把我的方法和解决办法写出来,希望可以对你有一点帮助。逻辑方面可以先想想,我需要这个系统实现什么功能,就药店管理系统来讲,这个我觉得增删改查是必须的,再加一个补货提醒,剩下的就是什么几家药店一起搞,这样用户知道库存和药店位置可以做出最优选择。然后搞了两个端口进行,一个用户端,一个工作人员端口,这样的话显示菜单不同,功能也可以分开实现。(这里可以写三个文本,一个存药店信息,一个存药品信息,一个存所有的用户和工作人员的ID和密码)。代码实现按照运行显示顺序排列代_c语言药店管理系统设计报告
文章浏览阅读243次,点赞5次,收藏3次。高精度3D点云配准利器:ct_icp项目地址:https://gitcode.com/jedeschaud/ct_icp项目简介ct_icp 是一个开源的C++库,专注于CT(Computed Tomography)扫描数据和3D点云之间的高精度配准。该项目由Jedéschaud开发并维护,旨在提供一种高效、精确的方法,用于医学影像处理、工业检测等领域中的三维重建和数据分析。技术解析ct...
文章浏览阅读652次。问题描述从数据库(Mongodb)中取的身份证号是lang类型,需要转换成字符串类型。拿到这个需求的时候没有多想,上来就是toString,+'',类似:var idCardNo = 110105199805241789;var idString = idCardNo + '';// 或者 var idString = idCardNo.toString();console.log(idString,typeof(idString));// 110105199805241800 string_身份证号转字符串出现问题
文章浏览阅读1.3w次,点赞8次,收藏37次。看到一篇知乎大神Flood Sung发表在CVPR2018上的paper,介绍了一种基于metric的模式识别方法,创新之处在于它不同于常用的matric-based方法,使用人为定义的度量,像简单的欧式距离、马氏距离,而是采用了用神经网络去训练这个度量,模型虽然简单,但是效果却很显著。1、度量(Metric)先说一下关于度量这个概念:在数学中,一个度量(或距离函数)是一个定义集合中元素之间距离的..._度量学习的作用