Springboot教程(五)——单元测试

idea中一般使用JUnit进行单元测试 

基本使用

我们可以在idea的test文件夹下的XXXXApplicationTests内进行单元测试:

可以在@Test标注的方法上写测试代码: 

@SpringBootTest
class C0101ApplicationTests {@Testfun contextLoads() {println("Hello World")}}

我们也可以写多个测试方法:

@SpringBootTest
class C0101ApplicationTests {@Testfun test1() {println("test1")}@Testfun test2() {println("test2")}}

我们也可以在测试类内使用@Autowired注解,如我们可以自动注入写好的服务:

@Autowired
lateinit var testService: TestService

我们来举个例子,先创建一个服务:

package com.example.c0101.serviceimport org.springframework.stereotype.Service@Service
class TestService {fun check(username: String, password: String): Boolean{return username == "admin" && password == "123456"}
}

然后在测试类内使用Autowired自动注入服务,并进行测试:

package com.example.c0101import com.example.c0101.service.TestService
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest@SpringBootTest
class C0101ApplicationTests {@Autowiredlateinit var testService: TestService@Testfun test() {println(testService.check("111", "123"))println(testService.check("admin", "123456"))}}

控制台输出:

...
false
true
...

测前准备和测后收尾

我们可以用以下注解实现测前准备和测后收尾:

  • @BeforeEach:在每一个测试方法执行前执行,其标注的方法可以传入一个TestInfo类型的参数,为当前测试信息的对象
  • @AfterEach:在每一个测试方法执行后执行,其标注的方法可以传入一个TestInfo类型的参数,为当前测试信息的对象
  • @BeforeAll:在所有测试方法执行前只执行一次
  • @AfterAll:在所有测试方法执行后只执行一次

另外,@BeforeAll和@AfterAll标注的方法需要为静态,在kotlin中需要放在companion object的代码块下,并用@JvmStatic注解标注


以下代码展示了这些注解的用法:

package com.example.c0101import com.example.c0101.service.TestService
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInfo
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest@SpringBootTest
class C0101ApplicationTests {@BeforeEachfun beforeEach(info: TestInfo){println("即将进入测试方法:${info.testMethod.get()}")}@AfterEachfun afterEach(info: TestInfo){println("已经离开测试方法:${info.testMethod.get()}")}companion object {@JvmStatic@BeforeAllfun beforeAll(){println("即将进入测试")}@JvmStatic@AfterAllfun afterAll(){println("测试已完成")}}@Testfun test() {println("Hello World")}}

控制台输出:

...
即将进入测试
...
即将进入测试方法:public void com.example.c0101.C0101ApplicationTests.test()
Hello World
已经离开测试方法:public void com.example.c0101.C0101ApplicationTests.test()
测试已完成
...

设置测试用例

要想设置测试用例,需要使用@ParameterizedTest注解,该注解可以传入name参数,可以为测试方法起别名。另外,可以用@ValueSource注解设置参数源:

@ParameterizedTest
@ValueSource(ints = [1, 2, 3, 4, 5])
fun test(num: Int) {println("$num")
}

注意,被@ParameterizedTest注解标注的测试方法就不需要用@Test注解标注了

JUnit会将所有的测试用例都测试一遍,因此这个测试方法会被执行5次:

...
1
2
3
4
5
...

我们也可以用@MethodSource注解设置测试用例,它将会把一个静态方法的返回值作为测试用例:

companion object{@JvmStaticfun getInt(): Stream<Int>{return Stream.of(1, 2, 3, 4, 5)}
}@ParameterizedTest
@MethodSource("getInt")
fun test(num: Int) {println("$num")
}

注意:这里面的Stream是java.util.stream下的Stream类

使用这种方法,我们就可以传入多个参数了:

companion object{@JvmStaticfun getProducts(): Stream<Arguments>{return Stream.of(Arguments.of("鼠标", 49.9),Arguments.of("键盘", 59.9))}
}@ParameterizedTest
@MethodSource("getProducts")
fun test(name: String, price: Double) {println("$name 卖 $price 元")
}

输出:

...
鼠标 卖 49.9 元
键盘 卖 59.9 元
...

断言

测试人员可以断言一件事是真的,如果这件事不是真的,则测试失败

JUnit提供了Assertions类,用于进行断言:

@Test
fun test() {Assertions.assertTrue(1 > 2)
}

这段代码断言了1>2是真的,如果不是真的(当然不是真的),则测试失败:

idea提示测试失败
标题

断言的应用

还记得之前的测试服务的代码吗,这个服务在传入用户名为admin且密码为123456后应该返回true,如果返回的不是true,说明这个服务写错了;同理,如果传入的用户名不是admin或密码不是123456,则应该返回false,如果返回的不是false,同样说明这个服务写错了。我们可以用断言来测试这个功能:

@Autowired
lateinit var testService: TestService@Test
fun test() {Assertions.assertTrue(testService.check("admin", "123456"))Assertions.assertTrue(!testService.check("aaa", "123"))
}

可以看到,测试通过,说明check没有写错

模拟Servlet对象

如果要测试controller等需要使用Servlet对象(例如HttpServletRequest)的方法,就需要模拟Servlet对象,我们可以在测试类自动注入以下对象模拟:

@Autowired
lateinit var mockHttpServletRequest: MockHttpServletRequest
@Autowired
lateinit var mockHttpServletResponse: MockHttpServletResponse
@Autowired
lateinit var mockHttpSession: MockHttpSession

这些代码在idea里可能会报错,不过没有关系

另外,在测试contoller时,同样需要@Autowired:

@Autowired
lateinit var controller: TestController

我们来举个模拟Servlet的例子:

先创建一个controller:

package com.example.c0101.controllerimport jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import jakarta.servlet.http.HttpSession
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController@RestController
class TestController {@RequestMappingfun index(request: HttpServletRequest, response: HttpServletResponse, session: HttpSession): String{response.status = 404return "Hello World"}}

当访问主页时,会设置状态码为404,并返回Hello World

接下来编写测试类:

package com.example.c0101import com.example.c0101.controller.TestController
import com.example.c0101.service.TestService
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.mock.web.MockHttpSession@SpringBootTest
class C0101ApplicationTests {@Autowiredlateinit var controller: TestController@Autowiredlateinit var mockHttpServletRequest: MockHttpServletRequest@Autowiredlateinit var mockHttpServletResponse: MockHttpServletResponse@Autowiredlateinit var mockHttpSession: MockHttpSession@Testfun test() {val res = controller.index(mockHttpServletRequest, mockHttpServletResponse, mockHttpSession)Assertions.assertTrue(mockHttpServletResponse.status == 404)println(res)}}

测试类中,我们断言了状态码一定是404,并输出了返回结果

控制台输出如下:

...
Hello World
...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/717755.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基础二分学习笔记

模板 : 个人倾向第一种 ; 整数二分 : 最大化查找 : 可行区域在左侧 : 查找最后一个<q的数的下标 : int find(int q){// 查找最后一个 < q 的下标 int l 0 , r n 1 ;while(l 1 < r){int mid l r >> 1 ;if(a[mid]<q) l mid ;else r mid ;}return…

土壤类型数据

国家地球系统科学数据中心

AGM CPLD (AGRV2K )的时钟(外部时钟和片上内部振荡器)

AGM CPLD &#xff08;AGRV2K &#xff09;的时钟(外部时钟和片上内部振荡器) 外部晶振 与 内部振荡器&#xff1a; mcu 和 cpld 联合编程时&#xff0c; 整颗芯片需要一颗外部晶振。 &#xff08;芯片有内部振荡器&#xff0c; 但误差较大&#xff0c; 校准后 5%以内误差&…

Electron通过预加载脚本从渲染器访问Node.js

问题&#xff1a;如何实现输出Electron的版本号和它的依赖项到你的web页面上&#xff1f; 答案&#xff1a;在主进程通过Node的全局 process 对象访问这个信息是微不足道的。 然而&#xff0c;你不能直接在主进程中编辑DOM&#xff0c;因为它无法访问渲染器 文档 上下文。 它们…

【软考】数据库的三级模式

目录 一、概念1.1 说明1.2 数据库系统体系结构图 二、外模式三、概念模式四、内模式 一、概念 1.1 说明 1.数据的存储结构各不相同&#xff0c;但体系结构基本上具有相同的特征&#xff0c;采用三级模式和两级镜像 2.数据库系统设计员可以在视图层、逻辑层和物理层对数据进行抽…

matplotlib散点图

matplotlib散点图 假设通过爬虫你获取到了北京2016年3, 10月份每天白天的最高气温(分别位于列表a, b), 那么此时如何寻找出气温和随时间(天)变化的某种规律? from matplotlib import pyplot as pltx_3 range(1, 32) x_10 range(51, 82)y_3 [11,17,16,11,12,11,12,6,6,7,8…

试手一下CameraX(APP)

书接上回。 首先还是看谷歌的官方文档&#xff1a; https://developer.android.com/media/camera/camerax?hlzh-cn https://developer.android.com/codelabs/camerax-getting-started?hlzh-cn#1 注&#xff1a;这里大部分内容也来自谷歌文档。 官方文档用的是Kotlin&…

Day14:信息打点-主机架构蜜罐识别WAF识别端口扫描协议识别服务安全

目录 Web服务器&应用服务器差异性 WAF防火墙&安全防护&识别技术 蜜罐平台&安全防护&识别技术 思维导图 章节知识点 Web&#xff1a;语言/CMS/中间件/数据库/系统/WAF等 系统&#xff1a;操作系统/端口服务/网络环境/防火墙等 应用&#xff1a;APP对象/…

小程序图形:echarts-weixin 入门使用

去官网下载整个项目&#xff1a; https://github.com/ecomfe/echarts-for-weixin 拷贝ec-canvs文件夹到小程序里面 index.js里面的写法 import * as echarts from "../../components/ec-canvas/echarts" const app getApp(); function initChart(canvas, width, h…

Vscode 使用SSH远程连接树莓派的教程(解决卡在Downloading with wget)

配置Vscode Remote SSH 安装OpenSSH 打开Windows开始页面&#xff0c;直接进行搜索PowerShell&#xff0c;打开第一个Windows PowerShell&#xff0c;点击以管理员身份运行 输入指令 Get-WindowsCapability -Online | ? Name -like OpenSSH* 我是已经安装好了&#xff0c;…

学会玩游戏,智能究竟从何而来?

最近在读梅拉妮米歇尔《AI 3.0》第三部分第九章&#xff0c;谈到学会玩游戏&#xff0c;智能究竟从何而来&#xff1f; 作者: [美] 梅拉妮米歇尔 出版社: 四川科学技术出版社湛庐 原作名: Artificial Intelligence: A Guide for Thinking Humans 译者: 王飞跃 / 李玉珂 / 王晓…

基于springboot实现计算机类考研交流平台系统项目【项目源码+论文说明】

基于springboot实现计算机类考研交流平台系统演示 摘要 高校的大学生考研是继高校的高等教育更上一层的表现形式&#xff0c;教育的发展是我们社会的根本&#xff0c;那么信息技术的发展又是改变我们生活的重要因素&#xff0c;生活当中各种各样的场景都存在着信息技术的发展。…

Debezium发布历史163

原文地址&#xff1a; https://debezium.io/blog/2023/09/23/flink-spark-online-learning/ 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. Online machine learning with the data streams from the database …

SpringBlade CVE-2022-27360 export-user SQL 注入漏洞分析

漏洞描述 SpringBlade是一个基于Spring Cloud和Spring Boot的开发框架&#xff0c;旨在简化和加速微服务架构的开发过程。它提供了一系列开箱即用的功能和组件&#xff0c;帮助开发人员快速构建高效可靠的微服务应用。该产品/api/blade-user/export-user接口存在SQL注入。 漏…

Java - List集合与Array数组的相互转换

一、List 转 Array 使用集合转数组的方法&#xff0c;必须使用集合的 toArray(T[] array)&#xff0c;传入的是类型完全一样的数组&#xff0c;大小就是 list.size() public static void main(String[] args) throws Exception {List<String> list new ArrayList<S…

分布式ID生成策略-雪花算法Snowflake

分布式ID生成策略-雪花算法Snowflake 一、其他分布式ID策略1.UUID2.数据库自增与优化2.1 优化1 - 共用id自增表2.2 优化2 - 分段获取id 3.Reids的incr和incrby 二、雪花算法Snowflake1.雪花算法的定义2.基础雪花算法源码解读3.并发1000测试4.如何设置机房和机器id4.雪花算法时钟…

【misc | CTF】BUUCTF 二维码

天命&#xff1a;这题使用到脚本暴力破解压缩包文件里面的密码&#xff0c;还是比较有意思的 一开始是一个二维码&#xff0c;扫码进去有一个假flag 扔进图片隐写工具&#xff0c;啥也没有&#xff0c;都是同一个二维码 使用工具&#xff1a;foremost&#xff0c;直接分离图片&…

【详识JAVA语言】抽象类和接口

抽象类 抽象类概念 在面向对象的概念中&#xff0c;所有的对象都是通过类来描绘的&#xff0c;但是反过来&#xff0c;并不是所有的类都是用来描绘对象的&#xff0c;如果 一个类中没有包含足够的信息来描绘一个具体的对象&#xff0c;这样的类就是抽象类。 比如&#xff1a;…

水印相机小程序源码

水印相机前端源码&#xff0c;本程序无需后端&#xff0c;前端直接导入即可&#xff0c;没有添加流量主功能&#xff0c;大家开通后自行添加 源码搜索&#xff1a;源码软件库 注意小程序后台的隐私权限设置&#xff0c;前端需要授权才可使用 真实时间地址拍照记录&#xff0c…

Endnote x9 最快方法批量导入.enw格式文件

按照网上看到的一个方法直接选中所有enw批量拖拽到 All references 附件不行啊&#xff0c; 以为只能写bat脚本方式了 经过一番尝试&#xff0c;惊人的发现拖到下面这个符号的地方就行了&#xff01;&#xff01;&#xff01; 如果不成功的话&#xff0c;可能&#xff1a; 我…