Spring Boot 单元测试(Unit test)

一、 单元测试的概念

概念:

  1. 单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。在Java中单元测试的最小单元是类。
  2. 单元测试是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。执行单元测试,就是为了证明这 段代码的行为和我们期望是否一致。

单元测试引用:

  1. 众所周知,通过spring initialize创建的Spring Boot项目会在Maven中自动携带很多starter依赖:

其中包含了一个名为spring-boot-starter-test的依赖,本文是围绕这个依赖展开。

  1. Spring Boot中引入单元测试很简单,添加如下依赖(即spring-boot-starter-test依赖):
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
</dependency>

  1. spring-boot-starter-test有如下几个库:

spring-boot-starter-testUML图:

在这里插入图片描述

序号 库名的解释
1 JUnit 5:包含兼容 JUnit 4,Java 应用程序单元测试的事实标准
2 Spring Test 和 SpringBootTest:对Spring Boot应用程序的公共和集成测试支持
3 AssertJ:流式断言库
4 Hamcrest:匹配对象库
5 Mockito:Java 模拟框架
6 JSONassert:JSON 断言库
7 JsonPath:JSON XPath

二、单元测试的作用

在没有接触单元测试之前我们是怎么做测试的?一般有两个方法:

方法 弊端
方法一:启动整个应用,像用户正常操作一样。点击界面按钮,调用一个 API 等。 每次测试都要启动整个项目
方法二:在代码某个地方写一个临时入口,例如 java 的 main 方法,测试某个方法或者某个类。 入口用完要删除,不然会影响项目的运行速度或效率

在时间允许的情况下,编写单元测试是程序员对代码的自测,这是对自己代码的负责。

写单元测试的两个动机:

  1. 保证或验证实现功能。
  2. 保护已经实现的功能不被破坏。

三、Spring Boot引入的MockMvc的概念

  1. 什么是Mock?

在面向对象的程序设计中,模拟对象(英语:mock object)是以可控的方式模拟真实对象行为的假对象。在编程过程中,通常通过模拟一些输入数据,来验证程序是否达到预期结果。

  1. 为什么使用Mock对象?

使用模拟对象,可以模拟复杂的、真实的对象行为。如果在单元测试中无法使用真实对象,可采用模拟对象进行替代。

  1. MockMvc的概念

MockMvc是由spring-test包提供,实现了对Http请求的模拟,能够直接使用网络的形式,转换到Controller的调用,使得测试速度快、不依赖网络环境。同时提供了一套验证的工具,结果的验证十分方便。

接口MockMvcBuilder,提供一个唯一的build方法,用来构造MockMvc。主要有两个实现:StandaloneMockMvcBuilder和DefaultMockMvcBuilder。

实例化方法 实例&解释
方法一 mockMvc = MockMvcBuilders.standaloneSetup(new HelloWorldController()).build();通过参数指定一组控制器,这样就不需要从上下文获取了
方法二 mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();指定WebApplicationContext,将会从该上下文获取相应的控制器并得到相应的MockMvc
  1. MockMVC的基本步骤
    (1) mockMvc.perform执行一个请求。
    (2) MockMvcRequestBuilders.get(“XXX”)构造一个请求。
    (3) ResultActions.param添加请求传值
    (4) ResultActions.accept()设置返回类型
    (5) ResultActions.andExpect添加执行完成后的断言。
    (6) ResultActions.andDo添加一个结果处理器,表示要对结果做点什么事情,比如处使用print()输出整个响应结果信息。
    (7) ResultActions.andReturn表示执行完成后返回相应的结果。

四、Service层的单元测试

(以下图片均引自文末学习文章,因为公司项目不方便截图)

第一步:Spring Boot中单元测试类写在src/test/java目录下,你可以手动创建具体测试类,也可以通过IDEA自动创建测试类,如下图:(注:双击打开相应代码的编辑器页面,再点击菜单栏的Navigate可以看到Test菜单)


或者编辑器里面在类名的右键菜单,点击Go To-->Test即可。

第二步:按照第一步的方法,点击测试后,出现图一的对话框(如果想要测试的类已经存在测试类了会被列出来,也可以重新创建一个新的测试类),点击”Create New Test…”会弹出图二的对话框,可以选择是否生成setUp以及要测试的成员方法等:

图一


图二


建议第一个选项为Junit5

第三步:至此Service层的测试类就创建好了,测试类自动生成到了src/test/java目录下<u style="box-sizing: border-box; outline: 0px; overflow-wrap: break-word;">项目的同级目录中</u>,如下图:

在这里插入图片描述

Service层测试代码如下:

@SpringBootTest
@RunWith(SpringRunner.class)
public class XXXServiceTest {
    @Resource
    private XXXService XXXService;

    @Test
    public void conflictTime() {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate start = LocalDate.parse("2020-10-26", dtf);
        LocalDate end = LocalDate.parse("2020-10-31", dtf);
        Integer integer = XXXService.ConflictTime("10000001", start, end);
        Assert.assertThat(integer, Matchers.notNullValue());//assertThat断言后面介绍    
   }
}

注解解释:

@SpringBootTest:获取启动类,加载配置,寻找主配置启动类(被 @SpringBootApplication 注解的) @RunWith(SpringRunner.class):让JUnit运行Spring的测试环境,获得Spring环境的上下文的支持

五、Controller层的单元测试

创建测试类步骤见第四部分,此处略。

  • 第四部分只是针对Service层做了测试,但是咱么也需要对Controller层(API)做测试,这时候就用到MockMvc了,它使得你无需启动项目工程就能测试这些接口。
  • MockMvc实现了对Http请求的模拟,能够直接使用网络的形式,转换到Controller的调用,这样可以使得测试速度快、不依赖网络环境,而且提供了一套验证的工具,这样可以使得请求的验证统一而且很方便。

Controller层部分的代码小名将分为三个代码块讲解,里面有看不懂的代码先不要着急哦😄,小名会在第五部分结尾处给大家汇总解答的,大家要坚持看到最后哟!😁

代码块一:

@SpringBootTest
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
public class DfTaskRecordControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Before
    public void setUp() throws Exception {
       System.out.println("---------------start---------------");
       save();
       get();
       System.out.println("================end================");
    }

注解解释:
@SpringBootTest>:获取启动类,加载配置,寻找主配置启动类(被 @SpringBootApplication 注解的)

@RunWith(SpringRunner.class)>:让JUnit运行Spring的测试环境,获得Spring环境的上下文的支持 @AutoConfigureMockMvc:用于自动配置MockMvc,配置后MockMvc类可以直接注入,相当于new MockMvc @Before:初始化方法 ,对于每一个测试方法都要执行一次

代码块二:

    @Test
    @Transactional
    @Rollback()
    public void save() throws Exception {
        String json"{……}";
        //执行一个RequestBuilder请求,会自动执行SpringMVC的流程并映射到相应的控制器执行处理;
        mockMvc.perform(MockMvcRequestBuilders
                .post("/XXX/save")
                .content(json.getBytes()) //传json参数
                .accept(MediaType.APPLICATION_JSON)
                .contentType(MediaType.APPLICATION_JSON_VALUE)
                .header("Authorization","Bearer ********-****-****-****-************")
        )
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(print());
    }

注解解释:
@Transactional:开启事务功能

@Rollback(): 事务回滚,默认是true

代码块三:

    @Test
    public void get() throws Exception{
        ResultActions resultActions = mockMvc.perform(MockMvcRequestBuilders
                .get("/XXX/get")
                .param("id", "**********")
                .header("Authorization", "Bearer ********-****-****-****-************")
        );
        resultActions.andReturn().getResponse().setCharacterEncoding("UTF-8");
        resultActions.andExpect(MockMvcResultMatchers.status().isOk()).andDo(print());

    }
}

/get运行结果如下:

在这里插入图片描述

现在小名将上面的一些琐碎的知识点汇总一下:

  1. mockMvc.perform:执行一个请求
  2. MockMvcRequestBuilders.get(“/XXX/get”):构造一个请求,Post请求使用.post方法
  3. contentType(MediaType.APPLICATION_JSON_VALUE):代表发送端发送的数据格式是application/json;charset=UTF-8
  4. accept(MediaType.APPLICATION_JSON):代表客户端希望接受的数据类型为application/json;charset=UTF-8
  5. header(“Authorization”,“Bearer XXXX”):代表在报文头添加一些必须的信息,这里添加的是token
  6. ResultActions.andExpect:添加执行完成后的断言
  7. ResultActions.andExpect(MockMvcResultMatchers.status().isOk()):方法看请求的状态响应码是否为200如果不是则抛异常,测试不通过
  8. ResultActions.andDo:添加一个结果处理器,表示要对结果做点什么事情,比如此处使用print():输出整个响应结果信息

六、断言的概念

  1. 断言(assert),是编程术语,表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真。可以在任何时候启用和禁用断言验证,因此可以在测试时启用断言而在部署时禁用断言。
  2. 使用断言是判断一个函数或对象的一个方法所产生的结果是否符合你期望的那个结果。

七、新断言assertThat使用

JUnit 4.4 结合 Hamcrest 提供了一个全新的断言语法——assertThat。程序员可以只使用 assertThat 一个断言语句,结合 Hamcrest 提供的匹配符,就可以表达全部的测试思想。

assertThat 的优点:
优点 1:以前 JUnit 提供了很多的 assertion 语句,如:assertEquals,assertNotSame,assertFalse,assertTrue,assertNotNull,assertNull 等,现在有了 JUnit 4.4,一条 assertThat 即可以替代所有的 assertion 语句,这样可以在所有的单元测试中只使用一个断言方法,使得编写测试用例变得简单,代码风格变得统一,测试代码也更容易维护。

优点 2:assertThat 使用了 Hamcrest 的 Matcher 匹配符,用户可以使用匹配符规定的匹配准则精确的指定一些想设定满足的条件,具有很强的易读性,而且使用起来更加灵活。

优点 3:assertThat 不再像 assertEquals 那样,使用比较难懂的“谓宾主”语法模式(如:assertEquals(3, x);),相反,assertThat 使用了类似于“主谓宾”的易读语法模式(如:assertThat(x,is(3));),使得代码更加直观、易读。

assertThat 的基本语法如下:

assertThat( [value], [matcher statement] );

value :接下来想要测试的变量值; matcher statement :使用 Hamcrest 匹配符来表达的对前面变量所期望的值的声明,如果 value 值与 matcher statement 所表达的期望值相符,则测试成功,否则测试失败。

八、Postman与Spring Boot 单元测试的区别

  • Spring Boot的单元测试主要针对方法层面,可以测试Service层这类非对外暴露的接口的类中方法,并且可一次性批量测试多个方法、支持事务回滚。
  • Postman针对接口进行http测试,我平时这个比较多,创建的测试接口可保存、分类。

九、Postman基本用法

Postman是一款功能强大的网页调试与发送网页HTTP请求的工具。Postman能够发送任何类型的HTTP请求(GET, HEAD, POST,PUT..),附带任何数量的参数和HTTP headers。支持不同的认证机制(basic, digest,OAuth),接收到的响应语法高亮(HTML,JSON或XML)。

安装Postman 官方网站:https://www.getpostman.com/apps

image

安装后,Postman是介样婶儿滴~~😊

在这里插入图片描述
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容