在使用@SpringBootTest测试时可以指定一个端口,如@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) 或 @SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT),这样在测试时会启动Spring内嵌的Http Server。 这时就可以使用一个RestTemplate 或者 TestRestTemplate。 使用RANDOM_PORT和DEFINED_PORT的区别在于前着使用的是配置文件中的端口号(server.port,默认值为8080),后者使用的是一个随机端口号。在进行并行测试的时候可以使用随机端口号以避免端口冲突。 看下测试代码: Web Server测试 这里依然使用SpringRunner执行测试。同时使用@SpringBootTest注解的RANDOM_PORT 模式来得到一个内嵌的WebServer运行当前应用。 测试代码中使用RestTemplate来触发请求,这个过程和使用外部服务器很像。 测试中的assertion现在有了一点儿变化,因为要验证的返回值由MockHttpServletResponse变成了ResponseEntity。 TestRestTemplate 因为使用了@SpringBootTest注解,就可以使用@Autowired注解来获取TestRestTemplate的实例。这个TestRestTemplate实例的作用和常见的RestTemplate实例几乎没有任何区别,只是添加了一些额外的能力。实际上,可以将TestRestTemplate视为RestTemplate在测试环境的装饰类。 参与测试的角色关系如下图: 关于性能 也许我们会觉得第一个方案会更加有性能优势,因为它不需要加载Spring Context。事实上确实如此。但是即使加载了SpringContext,也不会造成特别恐怖的影响,因为在同一个Test Suite中,已经加载的Spring Context是可以重用的。 不过Spring Context重用也会导致一些问题,比如一些测试方法对公共的Bean做了修改就可能会影响到其他测试方法。此时可以使用@DirtiesContext注解来要求重新加载Context。 总结 到现在为止我们从轻到重共介绍了四种SpringBoot Controller测试方案。 虽然我们的目标一直都是对Controller层进行测试,但是从第一种测试方案(Standalone MockMVC)到现在,测试的角度还是有些变化的。一开始我们只是会加载测试的Controller类,却不会加载其周边的一些角色如Filter或Advice。到现在这个方案里我们启动了内嵌的WebServer,加载了整个SpringBoot Context。 目前这个方案是提到的四个测试方案里最重的一个,也是离单元测试的概念最远的一个。 下面说几个使用建议: 如果在单元测试中关注Controller的逻辑,优先选择第一种方案:Standalone MockMVC方案; 如果要测试Web层的其它角色(Filter或Advice)的行为,优先选择第四种测试方案执行集成测试; 避免将单元测试和集成测试混在一起,最好分开来写。 其他 Spring Controller测试 – 01 概述 Spring Controller测试 – 02 Standalone MockMVC Spring Controller测试 – 03 WebContext & MockMVC Spring Controller测试 – 04 SpringBootTest & MockMVC Spring Controller测试 – 05 SpringBootTest & WebServer 示例代码可在CSDN下载,地址:https://download.csdn.net/download/tianxiexingyun/11065824 参考文档:https://thepracticaldeveloper.com/2017/07/31/guide-spring-boot-controller-tests/
[阅读更多...]-
Spring Controller层测试 – 05 SpringBootTest & WebServer
-
Spring Controller层测试 – 04 SpringBootTest & MockMVC
这种测试方案会加载完整的SpringContext,但我们仍然不需要Web Server,需要继续通过MockMVC来模拟请求。 在测试的时候主要用到了@SpringBootTest注解。看下代码: @SpringBootTest和@AutoConfigureMockMvc 使用@SpringBootTest注解会加载整个Context。这样我们可以自动获得所有在Context中注入的Bean,以及从application.properties中加载的配置信息。 在@SpringBootTest中声明webEnvironment为WebEnvironment.MOCK(默认值就是WebEnvironment.MOCK)后,结合@AutoConfigureMockMvc注解,在测试的时候会得到一个模拟的Web/Servlet环境。 因为没有Web Server,所以就无法使用RestTemplate,也就只能继续使用MockMVC了。这次MockMVC的实例是由@AutoConfigureMockMvc注解来完成的。这归功于SpringBoot的自动化配置。 所有参与测试的对象的关系如下图: 总结 这种测试方案更倾向于集成测试。它的关注点主要在于SpringBoot不同类之间的交互。 在这个测试方案中,请求仍然是通过MockMVC模拟的。不过因为有一个完整的Context,请求处理过程中的所有逻辑都是真实的,请求返回结果也是真实的。因此测试效果和使用Web Server几乎是差不多的了。 如果还是要只测试Controller中的逻辑,也可以继续使用 @MockBean注解来mock一个IWorkerService实例来覆盖Context中已有的实例。即使使用了真正的WebServer,也可以继续使用MockBean。同样在测试中也需要继续mock数据。 概括来说,这种测试的位置稍显尴尬:如果要执行单元测试来测试WEB层的逻辑,建议优先第二种方案;如果要执行集成测试,启动一个真正的Web Server,使用RestTemplate进行测试会更彻底也更加方便。 Spring Controller测试 – 01 概述 Spring Controller测试 – 02 Standalone MockMVC Spring Controller测试 – 03 WebContext & MockMVC Spring Controller测试 – 04 SpringBootTest & MockMVC Spring Controller测试 – 05 SpringBootTest & WebServer 其他:示例代码可在CSDN下载,地址:https://download.csdn.net/download/tianxiexingyun/11065824
[阅读更多...] -
Spring Controller层测试 – 03 WebContext & MockMVC
这种Controller层测试方案会(部分)加载Spring Application Context。不过仍然还是主要是用MockMVC来进行测试,也不需要部署WebServer。 示例代码如下: 和standalone MockMVC模式相比,这种测试方案主要有如下几点不同。 SpringRunner 这种测试是由SpringRunner来执行的。SpringRunner(部分)完成了Spring Context的初始化工作,在执行测试的时候,在日志开始的部分可以看到加载Context的内容。 MockMVC 自动化配置 使用@WebMVCTest注解可以完成MockMVC实例的自动化配置,以便于使用@Autowire注解来引用这个实例。同时,在@WebMVCTest注解中还指明了要测试的Controller类,这样Spring就会在Context中加载该Controller类及其相关的配置项。 此外,@WebMVCTest注解还会主动发现Controller类相关的Filter类和Controller Advice类并完成注入。这样,我们就不需要在setup()方法中再对其进行配置了。 使用MockBean 前面提到过这种测试方案是部分加载了Spring Context。原因就是@WebMVCTest在加载类的时候只会扫描含有@Controller,@ControllerAdvice, @JsonComponent,Filter,WebMvcConfigurer和HandlerMethodArgumentResolver这些注解或接口的类,也就是在三层模型中WEB层相关的类,而@Component注解的类则会被忽略掉。因此我们无法直接从Context获取IWorkerService实例。 因此测试中使用的WorkerService实例是通过@MockBean注解生成并注入到了Spring Context中的,并不是真正的WorkerService实例。 没有真正的服务调用 需要注意这里的返回值仍然是伪造的,在测试中也没有用到任何Web Server。 这次测试的主要关注点仍然是Controller类的内部逻辑,以及一些相关的角色如Filter和Controller Advice是如何影响Controller的返回值的。 总结 这次测试和使用MockMVC Standalone模式的主要区别在于不需要显式加载Controller相关的角色,因为这里使用到了Spring Context。参与测试的角色如下图: 如果我们创建了新的Filter、新的Controller Advice或者其他参与到WEB请求响应过程中的角色,也都会在测试中完成自动注入,不需要任何其它的配置。这和我们实际使用的场景非常类似。 这次测试可以算是向集成测试的一个小小过渡。这里我们没有做任何配置就实现了对Filter和Controller Advice的测试,如果有更多的其它角色,也可以直接集成到测试中。 Spring Controller测试 – 01 概述 Spring Controller测试 – 02 Standalone MockMVC Spring Controller测试 – 03 WebContext & MockMVC Spring Controller测试 – 04 SpringBootTest & MockMVC Spring Controller测试 – 05 SpringBootTest & WebServer 其他:示例代码可在CSDN下载,地址:https://download.csdn.net/download/tianxiexingyun/11065824
[阅读更多...] -
Spring Controller层测试 – 02 Standalone MockMVC
在Spring中,可以在Standalone模式下使用MockMVC来进行服务内测试,此时我们不会加载任何Context。来看个例子: MockitoJUnitRunner和MockMVC 代码中使用了MockitoJUnitRunner来运行单元测试。这个类是由Mockito提供的,并在内置的JUnit Runner上添加了一些功能:比如检测框架运行,初始化所有用@Mock注解声明的变量,这样就不需要再调用Mockito.initMocks()方法来显式mock对象了了。 代码中使用@Mock注解mock了一个IWorkerService的实例。这个IWorkerService的实例需要注入到WorkerController类的实例中。所以我们在声明WorkerController实例的时候使用了@InjectMocks注解。这样,通过这个注解我们使用mock出的IWorkerService实例替换了真正的WorkerServiceImpl实例。 在每个测试中,我们使用MockMvc对象来执行各种各样的模拟请求(如GET、POST等请求),之后我们也会收到一个MockHttpServletResponse对象作为返回值。注意这个返回值也不是一个真正的返回值,也是模拟的。 JacksonTester初始化 代码中使用JacksonTester.initFields()方法创建了一个JacksonTester对象。JacksonTester是Spring提供的一个工具类,可以使用这个JacksonTester对象来生成Worker实例的json字符串。 配置standalone MockMVC实例 每个测试在执行前都会调用setup方法。在setup方法中我们采用Standalone模式创建了MockMVC实例,并在配置中添加了要进行测试的Controller实例,以及新建的Controller Advice实例和HTTP Filter实例。当然也可以用类成员的形式创建Controller Advice和HTTPFilter实例。现在我们可以看到这种测试方法的不足了:所有Controller Advice和Filter中的逻辑都需要在setup()方法中进行配置。这是因为我们这里没有任何Spring Context可以注入Advice和Filter。 使用MockMVC测试ControllerAdvice和Filter 在测试方法getWhenNotExists()中,我们测试了id不存在的情况下,请求返回的状态码是否是HttpStatus.NOT_FOUND。如果返回值与预期一致的话,说明ControllerAdvice是能够正常工作的。 在最后的测试方法workerFilter()中,我们测试了返回结果中有没有WorkerFilter添加的请求头信息。如果返回结果的header中有添加的请求头信息,说明Filter是能够正常工作的。 也可以做个验证,注释掉setup()方法中关于ControllerAdvice和Filter的配置,然后再运行getWhenNotExists()和workerFilter()方法。可以看到测试会执行失败,因为相关的ControllerAdvice和Filter无法注入到运行环境中。 另外,在这里进行ControllerAdvice和Filter的测试多少有些不妥,因为我们的目标是测试Controller层的执行逻辑。对这二者的测试可以留到集成测试中进行。 总结 使用MockMVC Standalone模式测试对Controller层进行测试不会使用任何Spring容器,Controller层所依赖的其他服务均是mock出来的,也就是说除了Controller层的逻辑,其他相关数据都是模拟的。描述如下图: 这种测试方法的优势是: 不依赖Spring容器,启动和测试耗时较少 集中于Controller层逻辑,不受其他服务接口的影响 当然其优势也是其不足所在,我们通常不会在Controller层写入太多的业务逻辑,而是将业务逻辑写在Service层。但是因为这种测试方案中没有加载Spring容器,所以无法注入依赖的Service类,因此就无法测试到Service中实现的业务逻辑。 Spring Controller测试 – 01 概述 Spring Controller测试 – 02 Standalone MockMVC Spring Controller测试 – 03 WebContext & MockMVC Spring Controller测试 – 04 SpringBootTest & MockMVC Spring Controller测试 – 05 SpringBootTest & WebServer 其他:示例代码可在CSDN下载,地址:https://download.csdn.net/download/tianxiexingyun/11065824
[阅读更多...] -
Spring Controller层测试 – 01 概述
Spring Controller层(Web层或API层)的测试有多种方案。有人倾向于使用纯单元测试,有人则倾向于使用集成测试。 单元测试和集成测试 先来看一下单元测试和集成测试的概念。 单元测试 单元测试是对软件中的最小可验证单元进行检查和验证。比如对Java中的类和方法的测试。 测试原则: 尽可能保证测试用例相互独立(测试用例中不能直接调用其他类的方法,而应在测试用例中重写模拟方法); 此阶段一般由软件的开发人员来实施,用以检验所开发的代码功能是否符合自己的设计要求 单元测试的作用: 可以尽早的发现缺陷; 利于重构; 简化集成; 辅助文档; 辅助设计。 单元测试的不足: 每个测试单元至少需要3~5行代码,存在投入与产出的平衡。 集成测试 集成测试是根据集成测试计划,一边将模块或其他软件单位组合成越来越大的系统,一边运行该系统,以分析所组成的系统是否正确,各组成部分是否合拍。集成测试的策略主要有自顶向下和自底向上两种。 集成测试的作用: 目的是覆盖更多的执行路径; 发现单元之间接口的错误; 发现集成后的软件同软件需求不一致的地方。 不足在于: 关注的粒度较大,控制起来比较困难 比较来说单元测试更加重视过程,而集成测试更加重视结果。 Spring提供的Controller层测试方案 我们可以在不运行web server的情况下直接对Controller的逻辑进行测试。要执行这种测试,就需要mock服务器的行为,因此也有可能在测试中漏掉一些内容。不过无需担心,我们可以在集成测试中覆盖可能会漏掉的那部分内容。 当然也可以启动一个WebServer来执行Controller层的测试。这样就可以加载整个应用的Context,因此这种方案也可以被视为一种较重的方案。 在这里介绍三种Spring Controller层的测试方案: 在standalone模式下使用MockMVC方式; 结合SpringRunner使用MockMVC方式; 结合SpringBootTest和RestTemplate进行测试。 通常在执行单元测试的时候使用MockMVC方案,在进行集成测试的时候则建议使用RestTemplate方案。原因是使用MockMVC方式可以对Controller进行细粒度的断言,而RestTemplate则是能够使用Spring的WebApplicationContext(部分或全部)。 示例程序 为了便于说明,写了一个简单的SpringBoot Application来进行演示。 在应用中有如下几个类: WorkerController:WEB接口类; WorkerControllerAdvisor:Controller异常统一处理类,这里捕获了NonExistException并修改返回的status为404; WorkerFilter:过滤器类,在response中添加了header值X-CHOBIT-APP=chobit-header IWorkerService:服务接口类; WorkerServiceImpl:服务实现类,模拟了数据库操作。 示例代码可在CSDN下载,地址:https://download.csdn.net/download/tianxiexingyun/11065824 接下来分几篇文章来介绍几种测试方案。 Spring Controller测试 – 01 概述 Spring Controller测试 – 02 Standalone MockMVC Spring Controller测试 – 03 WebContext & MockMVC Spring Controller测试 – 04 SpringBootTest & MockMVC Spring Controller测试 – 05 SpringBootTest & WebServer
[阅读更多...] -
SpringBoot集成Jersey的单元测试方案
使用SpringBoot集成Jersey做单元测试时遇到了application.xml找不到的提示。详情如下: 测试使用的代码大致如下: 原因是SpringBoot的Context和Jersey的Context是不同的。要修复这个问题可以基于SpringBoot的Context来构建测试时Jersey的Context,但是这样做也会遇到一些问题。具体什么问题懒得说了。直接说解决方案:跳过Jersey的Context,不使用JerseyTest抽象类,直接自行创建WebTarget实例。 看一个测试超类代码示例好了: 就这样。 #############
[阅读更多...] -
在命令行执行JMeter测试计划
有时候会需要在linux的命令行上运行JMeter,简单说一下做法: 在图形界面上创建测试计划,并保存生成的test_plan.jmx文件; 将生成的test_plan.jmx文件上传到linux服务器; 在linux的命令行执行如下指令: 其中-n说明不是在图形界面下执行,-t指示了测试计划文件的位置。 还是写一个简单的示例吧。接下来创建一个HTTP请求的测试计划。 创建测试计划: 添加一个监听器: 这里将监听结果保存到文件。因为没办法直接通过图形界面查看运行结果,需要通过文件查看监听结果。 最后在命令行执行测试计划: 执行结束后可以将执行结果文件拷贝出来,在jmeter中打开查看。
[阅读更多...] -
使用JMeter + PerfMon做远程监控
本文假设已经安装好了JMeter 下载插件 PerfMon并不是JMeter原生的工具。要使用这个工具还需要下载一些插件。下载地址是jmeter-plugins.org。在JMeter Plugins的下载页面可以看到如下需要下载的内容: 下载用红框圈起来的前两个压缩包即可。 下载完成后。将第一个压缩包JMeterPlugins-Standard-1.3.1.zip解压到JMeter的安装目录下。第二个压缩包ServerAgent-2.2.1.zip解压后可以放在要监控的服务器上的任何位置。 使用 将第二个压缩包解压后,目录下有两个启动文件startAgent.sh和startAgent.bat。视平台选择启动文件启动PerfMon。 打开JMeter,添加线程组,在线程组下添加监听器jp@PerfMon Metrics Collector。 然后在PerfMon Metrics Collector中按自己的需求稍作配置即可。 此时照说是应该配置完了。我在官网和其他的地方找到的一些文章也说就这样就可以了。但是坑爹的是,做一下就会发现只这样还是不行的——一运行就会退出。我们还需要添加一个采样器Sampler。什么采样器都行,有了采样器就不会一点运行就退出。 关于怎么使用JMeter这里说的非常简略。想要多了解些可以看一下下文中的参考文档。这里不想反复说一些大家都知道的内容,只是稍作补充并略述心得而已。 最终还是发现PerfMon不是一个好的监控方案。因为CPU的消耗太大,一启动就会占用84%的CPU。用着真心不好,可以替代的方案也太多了,比如jvisualvm。 ######### 参考文档 JMeter Plugin官网: http://jmeter-plugins.org/ JMeter 服务器性能监测插件介绍:http://blog.csdn.net/defonds/article/details/41650813 Jmeter测试工具:http://www.cnblogs.com/zhangchaoyang/articles/2530731.html
[阅读更多...] -
基于JMeter进行分布式测试
我工作中的笔记本配置还可以。但是在测试一个简单的TCP连接时,发现把线程数设置为10000时,我的笔记本会很快死掉。最终实验出我的笔记本可以承受的安全线程数是5000。可是对应用的最低性能要求就是能承受1w的并发。此时可以采用基于JMeter的分布式测试方案。 如刚才提到的,要求测试应用在1w并发下的表现,而一部计算机所能承受的线程数是5000,那么需要两部计算机。 步骤 具体步骤如下: 为两部机器都安装JMeter; 定义两部机器的角色,一部是master,一部是slave;我们直接操作master,而slave只是负责分担master的压力; 获取slave的ip地址,比如是192.168.1.12; 在master的JMeter目录下打开bin目录,编辑jmeter.properties文件。找到“remote_hosts=127.0.0.1”这一行,将之修改为“remote_hosts=127.0.0.1,192.168.1.112:1099”。其中1099是master和slave的RMI通信端口。编辑完后记得保存; 打开master上的JMeter,点击运行菜单项,运行->远程启动->选择要启动的slave的IP;如果需要全部启动,运行->远程全部启动即可。 注意事项 有几点需要注意: 1. 启动jmeter-server服务时,提示: 这个是开始没有找到ApacheJmeter_core.jar,后来去JMETER_HOME目录下去查找,最后找到了,如果不希望看到Could not find的字样,可以配置一下jmeter_home的路径(即bin目录的上一级目录),这样启动jmeter-server服务时,就只会看到Found ApacheJMeter_core.jar,当远程访问时,会看到控制台上打印出一行:Starting the test on host [ip]:1099 @….(大概是这样的,@后面是执行开始的时间),远程执行结束,会打印一行:Finished the test on host [ip]:1099 @…,表示远程执行结束。 2. 留意一下1099端口,目前暂未确定这个端口是不是可以改的(按理说这个是可以从配置文件中修改的,目前还没有找到如何修改Agent上面的配置,Controller上面的还好修改) 3. Jmeter分布式控制过程中,各个Agent启动的线程数等于线程组中的配置,不是均分线程组中的配置。 参考文档 http://blog.chinaunix.net/uid-26884465-id-3419474.html http://www.51testing.com/html/12/252512-223613.html
[阅读更多...] -
JMeter监听器说明
JMeter的监听器可以理解为JMeter提供的测试分析工具(或者测试结果报告)。JMeter监听器的监听范围是当前节点及其子节点。JMeter提供了多种测试监听器,这里简单说几个用过的监听器。 创建测试计划 为了演示监视器的作用,我这里做了一个简单的HTTP请求测试。 如何创建测试计划就不多说了,可以参看这篇文章:《使用JMeter》 下图是线程组的配置: 下图是HTTP请求的配置参数: 启动测试,很快就可以生成测试结果报告。 用表格查看结果 下图是表格结果: 还有几个重要的指数: 简单说下表格中的字段: Sample#——每个请求的ID; StartTime——每个请求启动时间; SampleTime——响应每个请求的时间(以毫秒为单位); Status——请求状态,如果为勾则表示成功,如果为叉表示失败; Bytes——请求的字节数; Latency——延迟时间; ConnectTime——请求连接用时。 几个指数: 样本数目——样本总数(线程数*循环次数),或者说是发送给测试应用的请求总数; 最新样本——服务器响应最后一个请求的时间; 平均——请求响应时间的平均值; 偏离——请求响应时间的标准差。 聚合报告 下图是本次测试的聚合报告: Label——取样器名称; Samples——发给被测试应用的请求总数; Average——请求响应时间的平均值; Median——请求响应时间中值,即50%的请求响应时间都小于该值(一个统计学的概念); 90%Line——请求响应时间90%线,即90%的请求响应时间都小于该值; Min——最小响应时间; Max——最大响应时间; Error%——出错率(出错的请求数/所有的请求数); Throughput——吞吐量,每秒/每分钟(具体看“/”后面的单位)处理的请求数; KB/sec——每秒从服务器端接收到的数据量,相当于LoadRunner中的Throughput/Sec; 【注意】总体值并不是各列对应记录的累加。是以所有Samples为样本的统计值,如:总体Min=min{各个Samples的Min},总体Max=max{各个Samples的Max}。 Summary Report(总结报告) 下图是本次测试的Summary Report: 觉得这个和聚合报告一起看有点意思。 Label——取样器名称; Samples——发给被测试应用的请求总数; Average——请求响应时间的平均值; Median——请求响应时间中值,即50%的请求响应时间都小于该值(一个统计学的概念); 90%Line——请求响应时间90%线,即90%的请求响应时间都小于该值; Min:最小响应时间; Max:最大响应时间; Std.Dev——所有请求响应时间的标准差,即是“用表格查看结果”中的偏离; Error%——出错率(出错的请求数/所有的请求数); Throughput——吞吐量,每秒/每分钟(具体看“/”后面的单位)处理的请求数; KB/sec——每秒从服务器端接收到的数据量,相当于LoadRunner中的Throughput/Sec; Avg.Bytes——服务端返回给Request数据的平均值(服务端返回所有数据/请求数)。 图形结果 本次测试的图形结果如下图: 这里的几个指数上面都有提到。还是再说一次吧: 样本数目——样本总数(线程数*循环次数),或者说是发送给测试应用的请求总数; 最新样本——服务器响应最后一个请求的时间; 平均——请求响应时间的平均值; 偏离——请求响应时间的标准差; 吞吐量——每秒/每分钟(具体看“/”后面的单位)处理的请求数; 中值——请求响应时间中值,即50%的请求响应时间都小于该值。 查看结果树 下图是查看结果树: 简单说几个概念: 取样器结果——显示的是请求样本相关参数(客户端参数与响应参数) 请求——发送请求的具体值 响应数据——服务端返回的相应参数 ALL! 参考文章 http://www.51testing.com/html/12/252512-223091.html http://www.cnblogs.com/jackei/archive/2007/01/17/623166.html http://www.cnblogs.com/Carrie_Liang/archive/2008/11/10/1330997.html http://zuoye.baidu.com/question/1d937880d6e95b419397e16b267a71ba.html
[阅读更多...]