免费开发个人网站,莱芜信息港房产网,美术馆网站建设方案书,网络营销是一种营销方式#x1f648;作者简介#xff1a;练习时长两年半的Java up主 #x1f649;个人主页#xff1a;程序员老茶 #x1f64a; ps:点赞#x1f44d;是免费的#xff0c;却可以让写博客的作者开心好久好久#x1f60e; #x1f4da;系列专栏#xff1a;Java全栈#xff0c;… 作者简介练习时长两年半的Java up主 个人主页程序员老茶 ps:点赞是免费的却可以让写博客的作者开心好久好久 系列专栏Java全栈计算机系列火速更新中 格言种一棵树最好的时间是十年前其次是现在 动动小手点个关注不迷路感谢宝子们一键三连 目录 课程名Java内容/作用知识点/设计/实验/作业/练习学习SpringBoot的测试SpringBoot的测试1. 加载测试专用属性2. 加载测试专用配置3. Web环境模拟测试4. 数据层测试回滚5. 测试用例数据设定 课程名Java
内容/作用知识点/设计/实验/作业/练习
学习SpringBoot的测试
SpringBoot的测试
说完bean配置相关的内容下面要对前面讲过的一个知识做加强了测试。测试是保障程序正确性的唯一屏障在企业级开发中更是不可缺少但是由于测试代码往往不产生实际效益所以一些小型公司并不是很关注导致一些开发者从小型公司进入中大型公司后往往这一块比较短板所以还是要拿出来把这一块知识好好说说做一名专业的开发人员。
1. 加载测试专用属性
测试过程本身并不是一个复杂的过程但是很多情况下测试时需要模拟一些线上情况或者模拟一些特殊情况。如果当前环境按照线上环境已经设定好了例如是下面的配置
env:maxMemory: 32GBminMemory: 16GB 但是你现在想测试对应的兼容性需要测试如下配置
env:maxMemory: 16GBminMemory: 8GB 这个时候我们能不能每次测试的时候都去修改源码application.yml中的配置进行测试呢显然是不行的。每次测试前改过来每次测试后改回去这太麻烦了。于是我们就想需要在测试环境中创建一组临时属性去覆盖我们源码中设定的属性这样测试用例就相当于是一个独立的环境能够独立测试这样就方便多了。
临时属性
springboot已经为我们开发者早就想好了这种问题该如何解决并且提供了对应的功能入口。在测试用例程序中可以通过对注解SpringBootTest添加属性来模拟临时属性具体如下
//properties属性可以为当前测试用例添加临时的属性配置
SpringBootTest(properties {test.proptestValue1})
public class PropertiesAndArgsTest {Value(${test.prop})private String msg;Testvoid testProperties(){System.out.println(msg);}
} 使用注解SpringBootTest的properties属性就可以为当前测试用例添加临时的属性覆盖源码配置文件中对应的属性值进行测试。
临时参数
除了上述这种情况在前面讲解使用命令行启动springboot程序时讲过通过命令行参数也可以设置属性值。而且线上启动程序时通常都会添加一些专用的配置信息。作为运维人员他们才不懂java更不懂这些配置的信息具体格式该怎么写那如果我们作为开发者提供了对应的书写内容后能否提前测试一下这些配置信息是否有效呢当时是可以的还是通过注解SpringBootTest的另一个属性来进行设定。
//args属性可以为当前测试用例添加临时的命令行参数
SpringBootTest(args{--test.proptestValue2})
public class PropertiesAndArgsTest {Value(${test.prop})private String msg;Testvoid testProperties(){System.out.println(msg);}
} 使用注解SpringBootTest的args属性就可以为当前测试用例模拟命令行参数并进行测试。
说到这里好奇宝宝们肯定就有新问题了如果两者共存呢其实如果思考一下配置属性与命令行参数的加载优先级这个结果就不言而喻了。在属性加载的优先级设定中有明确的优先级设定顺序还记得下面这个顺序吗 在这个属性加载优先级的顺序中明确规定了命令行参数的优先级排序是11而配置属性的优先级是3结果不言而喻了args属性配置优先于properties属性配置加载。
到这里我们就掌握了如果在测试用例中去模拟临时属性的设定。
总结
加载测试临时属性可以通过注解SpringBootTest的properties和args属性进行设定此设定应用范围仅适用于当前测试用例
思考
应用于测试环境的临时属性解决了如果想在测试的时候临时加载一些bean能不做呢也就是说我测试时想搞一些独立的bean出来专门应用于测试环境能否实现呢咱们下一节再讲。
2. 加载测试专用配置
上一节提出了临时配置一些专用于测试环境的bean的需求这一节我们就来解决这个问题。
学习过Spring的知识我们都知道其实一个spring环境中可以设置若干个配置文件或配置类若干个配置信息可以同时生效。现在我们的需求就是在测试环境中再添加一个配置类然后启动测试环境时生效此配置就行了。其实做法和spring环境中加载多个配置信息的方式完全一样。具体操作步骤如下
步骤①在测试包test中创建专用的测试环境配置类
Configuration
public class MsgConfig {Beanpublic String msg(){return bean msg;}
} 上述配置仅用于演示当前实验效果实际开发可不能这么注入String类型的数据
步骤②在启动测试环境时导入测试环境专用的配置类使用Import注解即可实现
SpringBootTest
Import({MsgConfig.class})
public class ConfigurationTest {Autowiredprivate String msg;Testvoid testConfiguration(){System.out.println(msg);}
} 到这里就通过Import属性实现了基于开发环境的配置基础上对配置进行测试环境的追加操作实现了11的配置环境效果。这样我们就可以实现每一个不同的测试用例加载不同的bean的效果丰富测试用例的编写同时不影响开发环境的配置。
总结
定义测试环境专用的配置类然后通过Import注解在具体的测试中导入临时的配置例如测试用例方便测试过程且上述配置不影响其他的测试类环境
思考
当前我们已经可以实现业务层和数据层的测试并且通过临时配置控制每个测试用例加载不同的测试数据。但是实际企业开发不仅要保障业务层与数据层的功能安全有效也要保障表现层的功能正常。但是我们目的对表现层的测试都是通过postman手工测试的并没有在打包过程中体现表现层功能被测试通过。能否在测试用例中对表现层进行功能测试呢还真可以咱们下一节再讲。
3. Web环境模拟测试
在测试中对表现层功能进行测试需要一个基础和一个功能。所谓的一个基础是运行测试程序时必须启动web环境不然没法测试web功能。一个功能是必须在测试程序中具备发送web请求的能力不然无法实现web功能的测试。所以在测试用例中测试表现层接口这项工作就转换成了两件事一如何在测试类中启动web测试二如何在测试类中发送web请求。下面一件事一件事进行先说第一个
测试类中启动web环境
每一个springboot的测试类上方都会标准SpringBootTest注解而注解带有一个属性叫做webEnvironment。通过该属性就可以设置在测试用例中启动web环境具体如下
SpringBootTest(webEnvironment SpringBootTest.WebEnvironment.RANDOM_PORT)
public class WebTest {
} 测试类中启动web环境时可以指定启动的Web环境对应的端口springboot提供了4种设置值分别如下 MOCK根据当前设置确认是否启动web环境例如使用了Servlet的API就启动web环境属于适配性的配置DEFINED_PORT使用自定义的端口作为web服务器端口RANDOM_PORT使用随机端口作为web服务器端口NONE不启动web环境
通过上述配置现在启动测试程序时就可以正常启用web环境了建议大家测试时使用RANDOM_PORT避免代码中因为写死设定引发线上功能打包测试时由于端口冲突导致意外现象的出现。就是说你程序中写了用8080端口结果线上环境8080端口被占用了结果你代码中所有写的东西都要改这就是写死代码的代价。现在你用随机端口就可以测试出来你有没有这种问题的隐患了。
测试环境中的web环境已经搭建好了下面就可以来解决第二个问题了如何在程序代码中发送web请求。
测试类中发送请求
对于测试类中发送请求其实java的API就提供对应的功能只不过平时各位小伙伴接触的比较少所以较为陌生。springboot为了便于开发者进行对应的功能开发对其又进行了包装简化了开发步骤具体操作如下
步骤①在测试类中开启web虚拟调用功能通过注解AutoConfigureMockMvc实现此功能的开启
SpringBootTest(webEnvironment SpringBootTest.WebEnvironment.RANDOM_PORT)
//开启虚拟MVC调用
AutoConfigureMockMvc
public class WebTest {
}步骤②定义发起虚拟调用的对象MockMVC通过自动装配的形式初始化对象
SpringBootTest(webEnvironment SpringBootTest.WebEnvironment.RANDOM_PORT)
//开启虚拟MVC调用
AutoConfigureMockMvc
public class WebTest {Testvoid testWeb(Autowired MockMvc mvc) {}
}步骤③创建一个虚拟请求对象封装请求的路径并使用MockMVC对象发送对应请求
SpringBootTest(webEnvironment SpringBootTest.WebEnvironment.RANDOM_PORT)
//开启虚拟MVC调用
AutoConfigureMockMvc
public class WebTest {Testvoid testWeb(Autowired MockMvc mvc) throws Exception {//http://localhost:8080/books//创建虚拟请求当前访问/booksMockHttpServletRequestBuilder builder MockMvcRequestBuilders.get(/books);//执行对应的请求mvc.perform(builder);}
} 执行测试程序现在就可以正常的发送/books对应的请求了注意访问路径不要写http://localhost:8080/books因为前面的服务器IP地址和端口使用的是当前虚拟的web环境无需指定仅指定请求的具体路径即可。
总结
在测试类中测试web层接口要保障测试类启动时启动web容器使用SpringBootTest注解的webEnvironment属性可以虚拟web环境用于测试为测试方法注入MockMvc对象通过MockMvc对象可以发送虚拟请求模拟web请求调用过程
思考
目前已经成功的发送了请求但是还没有起到测试的效果测试过程必须出现预计值与真实值的比对结果才能确认测试结果是否通过虚拟请求中能对哪些请求结果进行比对呢咱们下一节再讲。
web环境请求结果比对
上一节已经在测试用例中成功的模拟出了web环境并成功的发送了web请求本节就来解决发送请求后如何比对发送结果的问题。其实发完请求得到的信息只有一种就是响应对象。至于响应对象中包含什么就可以比对什么。常见的比对内容如下 响应状态匹配 Test
void testStatus(Autowired MockMvc mvc) throws Exception {MockHttpServletRequestBuilder builder MockMvcRequestBuilders.get(/books);ResultActions action mvc.perform(builder);//设定预期值 与真实值进行比较成功测试通过失败测试失败//定义本次调用的预期值StatusResultMatchers status MockMvcResultMatchers.status();//预计本次调用时成功的状态200ResultMatcher ok status.isOk();//添加预计值到本次调用过程中进行匹配action.andExpect(ok);
}响应体匹配非json数据格式 Test
void testBody(Autowired MockMvc mvc) throws Exception {MockHttpServletRequestBuilder builder MockMvcRequestBuilders.get(/books);ResultActions action mvc.perform(builder);//设定预期值 与真实值进行比较成功测试通过失败测试失败//定义本次调用的预期值ContentResultMatchers content MockMvcResultMatchers.content();ResultMatcher result content.string(springboot2);//添加预计值到本次调用过程中进行匹配action.andExpect(result);
}响应体匹配json数据格式开发中的主流使用方式 Test
void testJson(Autowired MockMvc mvc) throws Exception {MockHttpServletRequestBuilder builder MockMvcRequestBuilders.get(/books);ResultActions action mvc.perform(builder);//设定预期值 与真实值进行比较成功测试通过失败测试失败//定义本次调用的预期值ContentResultMatchers content MockMvcResultMatchers.content();ResultMatcher result content.json({\id\:1,\name\:\springboot2\,\type\:\springboot\});//添加预计值到本次调用过程中进行匹配action.andExpect(result);
}响应头信息匹配 Test
void testContentType(Autowired MockMvc mvc) throws Exception {MockHttpServletRequestBuilder builder MockMvcRequestBuilders.get(/books);ResultActions action mvc.perform(builder);//设定预期值 与真实值进行比较成功测试通过失败测试失败//定义本次调用的预期值HeaderResultMatchers header MockMvcResultMatchers.header();ResultMatcher contentType header.string(Content-Type, application/json);//添加预计值到本次调用过程中进行匹配action.andExpect(contentType);
} 基本上齐了头信息正文信息状态信息都有了就可以组合出一个完美的响应结果比对结果了。以下范例就是三种信息同时进行匹配校验也是一个完整的信息匹配过程。
Test
void testGetById(Autowired MockMvc mvc) throws Exception {MockHttpServletRequestBuilder builder MockMvcRequestBuilders.get(/books);ResultActions action mvc.perform(builder);StatusResultMatchers status MockMvcResultMatchers.status();ResultMatcher ok status.isOk();action.andExpect(ok);HeaderResultMatchers header MockMvcResultMatchers.header();ResultMatcher contentType header.string(Content-Type, application/json);action.andExpect(contentType);ContentResultMatchers content MockMvcResultMatchers.content();ResultMatcher result content.json({\id\:1,\name\:\springboot\,\type\:\springboot\});action.andExpect(result);
}总结
web虚拟调用可以对本地虚拟请求的返回响应信息进行比对分为响应头信息比对、响应体信息比对、响应状态信息比对
4. 数据层测试回滚
当前我们的测试程序可以完美的进行表现层、业务层、数据层接口对应的功能测试了但是测试用例开发完成后在打包的阶段由于test生命周期属于必须被运行的生命周期如果跳过会给系统带来极高的安全隐患所以测试用例必须执行。但是新的问题就呈现了测试用例如果测试时产生了事务提交就会在测试过程中对数据库数据产生影响进而产生垃圾数据。这个过程不是我们希望发生的作为开发者测试用例该运行运行但是过程中产生的数据不要在我的系统中留痕这样该如何处理呢
springboot早就为开发者想到了这个问题并且针对此问题给出了最简解决方案在原始测试用例中添加注解Transactional即可实现当前测试用例的事务不提交。当程序运行后只要注解Transactional出现的位置存在注解SpringBootTestspringboot就会认为这是一个测试程序无需提交事务所以也就可以避免事务的提交。
SpringBootTest
Transactional
Rollback(true)
public class DaoTest {Autowiredprivate BookService bookService;Testvoid testSave(){Book book new Book();book.setName(springboot3);book.setType(springboot3);book.setDescription(springboot3);bookService.save(book);}
} 如果开发者想提交事务也可以再添加一个RollBack的注解设置回滚状态为false即可正常提交事务是不是很方便springboot在辅助开发者日常工作这一块展现出了惊人的能力实在太贴心了。
总结
在springboot的测试类中通过添加注解Transactional来阻止测试用例提交事务通过注解Rollback控制springboot测试类执行结果是否提交事务需要配合注解Transactional使用
思考
当前测试程序已经近乎完美了但是由于测试用例中书写的测试数据属于固定数据往往失去了测试的意义开发者可以针对测试用例进行针对性开发这样就有可能出现测试用例不能完美呈现业务逻辑代码是否真实有效的达成业务目标的现象解决方案其实很容易想测试用例的数据只要随机产生就可以了能实现吗咱们下一节再讲。
5. 测试用例数据设定
对于测试用例的数据固定书写肯定是不合理的springboot提供了在配置中使用随机值的机制确保每次运行程序加载的数据都是随机的。具体如下
testcase:book:id: ${random.int}id2: ${random.int(10)}type: ${random.int!5,10!}name: ${random.value}uuid: ${random.uuid}publishTime: ${random.long} 当前配置就可以在每次运行程序时创建一组随机数据避免每次运行时数据都是固定值的尴尬现象发生有助于测试功能的进行。数据的加载按照之前加载数据的形式使用ConfigurationProperties注解即可
Component
Data
ConfigurationProperties(prefix testcase.book)
public class BookCase {private int id;private int id2;private int type;private String name;private String uuid;private long publishTime;
} 对于随机值的产生还有一些小的限定规则比如产生的数值性数据可以设置范围等具体如下 ${random.int}表示随机整数${random.int(10)}表示10以内的随机数${random.int(10,20)}表示10到20的随机数其中()可以是任意字符例如[]!!均可
总结
使用随机数据可以替换测试用例中书写的固定数据提高测试用例中的测试数据有效性
往期专栏Java全栈开发数据结构与算法计算机组成原理操作系统数据库系统物联网控制原理与技术