assertJ-db 科普

前言

今日我们看看 java 大名鼎鼎的 assertj 是怎么做断言的

数据库断言

在实际的测试中我们总是跟业务打交道的。跟业务打交道一般很难避免验证数据库中的东西。尤其在接口测试中,一个常见的例子是你测试一个下单的接口。 接口返回可能就是成功过或者失败。你无法从返回值中判断订单的细节是否创建成功。这时候一般要查询数据库做断言。

demo

来看一下例子。

Request sql = new Request(dataSource,"select * from data where name = '"+data.getName()+"'");
assertThat(sql).row().column("name").value().isEqualTo(data.getName()).column("meta").value().isEqualTo(data.getMeta()).column("line_number").value().isEqualTo(data.getLineNumber()).column("size").value().isEqualTo(data.getSize()).column("type_id").value().isGreaterThan(data.getTypeId()).column("src_type_id").value().isEqualTo(data.getSrcTypeId());Request resourceSql = new Request(dataSource,"select * from resource where id = "+createdData.getResourceId()+"");
assertThat(resourceSql).row()
.column("uri").value().isEqualTo(data.getUri())
.column("protocol").value().isEqualTo(data.getProtocol().getValue());Request sql = new Request(dataSource,"select * from plan where name='"+copyPlanName+"'");
assertThat(sql).as("数据库中没有被保存的plan").hasNumberOfRows(1);

OK,assertJ-db 有一个对象叫 Request,它是对数据库请求的封装。创建的时候你需要传递一个 sql 和 dataSource(我使用的是 mybatis 的 dataSource)。接着就可以使用 assertJ 丰富的 data flow 式 API 进行断言了。 篇幅有限,介绍几个常用的使用方法。

元素

assertJ-db 有 4 个维度的元素用来断言。分别是:

  1. Table:表
  2. column:列
  3. row:行
  4. value:具体的一个字段的值

看我们第一个例子的代码中有如下一段:

Request sql = new Request(dataSource,"select * from data where name = '"+data.getName()+"'");assertThat(sql).row().column("name").value().isEqualTo(data.getName())

这里面我们分别取到了第一行 (row() 默认取第一行,也可以指定第几行) 中的名字叫 name 的列 (column 接受 string 类型的列名参数) 的值 (value)。因为我们是以 Request 的方式进行断言,所以就没有 table 什么事了. 我只举个简单的例子,这 4 种元素互相可以有各种组合的断言大家可以慢慢的探索。我只列出我个人最长用的使用方式。

compare api

assertJ-db 提供丰富的 compare api 来定制我们的断言。 我们看如下的代码:

assertThat(request).row(1).value().isEqualTo(2).value().isEqualTo(DateValue.of(1981, 10, 12)).hasValues("2", "1981-10-12", "October", "11", "00:41:08", null).value().isEqualTo("1.77").isNotEqualTo("1.78").value("size").isNotZero().isGreaterThan(1.5).isGreaterThanOrEqualTo(1.77).isLessThan(2).isLessThanOrEqualTo(1.77).value().isNull()Request sql = new Request(dataSource,"select * from plan where name='"+copyPlanName+"'");
assertThat(sql).hasNumberOfRows(1);

好有很多的 compare api 来为我们的 4 个元素进行验证。我不一一列举了。 它可以给我们各种维度的断言方式。

Request

在之前的介绍中我们总能看到 Request 的身影,这是我们最常用的断言模式。直接以一个 sql 筛选出要断言的数据。如下:

Request sql = new Request(dataSource,"select * from plan where name='"+copyPlanName+"'");
assertThat(sql).hasNumberOfRows(1).row().column("name").value().isEqualTo(copyPlanName)

Request 的目的就是根据 sql 筛选出我们要断言的数据,然后使用我们上面说的元素和 compare api 进行断言的工作。

Changes

之前我写监控式数据管理策略的时候写过 Changes 的使用。现在我再说一下吧。按惯例先看例子

public static Changes initChanges() {Changes change = null;if(changes != null) {change = changes;} else if(tables != null) {change = new Changes(tables);} else if(dataSource != null) {change = new Changes(dataSource);} else {if(source == null) {throw new ChangesException("you have not regiter any source to create changes. you should register changes, datasource,source or tables so that you can init changes to handle test datas");}change = new Changes(source);}return change;}

上面是我的数据管理部分初始化 changes 的代码。可以看到我们可以把 dataSource 传进去用来 diff 整个数据库。 也可以把 4 重元素的 table 传进去用来 diff 某一个或某一些表。changes 有两个方法,一个叫 start point,用来记录初始数据的状态,另一个叫 end point。用来记录结束的数据的状态。 changes 就是去 diff 这两个时间点的数据变化。不多说直接上一个例子:

Changes changes = new Changes(dataSource);changes.setStartPointNow();                // Start point (the moment when the changes start to be taken into account)makeChangesInTheData();changes.setEndPointNow();                  // End point (the moment when the changes stop to be taken into account)assertThat(changes).change()                               // First change.isCreation()                       // Assertion on the first change.rowAtStartPoint()                  // Row at the start point.doesNotExist()                 // Assertion on the row at start point of the first change.returnToChange()                   // Go back to the change.rowAtEndPoint()                    // Row at the end point.hasNumberOfColumns(6)          // Assertion on the row at end point of the first change.exists()                       // Another assertion on the same row.value(1)                       // Value at index 1 of the row at end point of the first change.isEqualTo("McGuiness")     // Assertion on the value.returnToRow()                  // Go back to the row.returnToChange()                   // Go back to the change.change()                               // Next change.rowAtEndPoint()                    // Row at end point of this change.hasValues(1, "Hewson", "Paul David", "Bono Vox", "1960-05-10", 1.75).column("surname")                  // Column with name is "surname" of the second change (note that returnToChange() is not mandatory).isModified()                   // Assertion on column.hasValues("Bono","Bono Vox").column()                           // Next column.isNotModified()                // Assertion on the column.valueAtEndPoint()              // Value at end point in the column after "surname" ("birth") of the second change.isEqualTo(DateValue.of(1960, 5, 10)).ofDeletion()                           // All the changes of deletion (note that the returnToXxxx() methods are not mandatory).change()                           // First change of these changes of deletion.isOnTable("albums").hasPksValues(15).changeOnTableWithPks("members", 5)     // Change with primary key 5 on "members" table.isCreation().rowAtEndPoint()                // Row at end point of change with primary key 5 on "members" table .hasValues(5, "McGuiness", "Paul", null,"1951-06-17", null);

这是 github 上官方的例子。如果你可以完全掌控你们的数据库,使用 changes 做断言不失为一个选择。下面再看一个例子

for(Change change:changeList){ChangeType type = change.getChangeType();String tableName = change.getDataName();if("CREATION".equals(type.name())){String id = change.getRowAtEndPoint().getValuesList().get(0).getColumnName();Object value = change.getRowAtEndPoint().getValuesList().get(0).getValue();String sql = "delete from "+tableName+" where "+id+" = "+value+"";deletionSQLs.add(sql);}else if("DELETION".equals(type.name())){String sql = "insert into "+tableName+" values(";List<Value> valuesList = change.getRowAtStartPoint().getValuesList();for(Value value : valuesList){Object columenValue = value.getValue();sql = sql + "'" +columenValue+"',";}sql = sql.substring(0, sql.length()-1);sql = sql +")";insertSQLs.add(sql);}else if("MODIFICATION".equals(type.name())){String sql = "update "+tableName+" SET ";List<Value> valuesList = change.getRowAtStartPoint().getValuesList();for(Value value : valuesList){Object columenValue = value.getValue();String columnName = value.getColumnName();sql = sql + columnName +"='"+columenValue+"' ,";}sql = sql.substring(0, sql.length()-1);sql = sql + " where "+valuesList.get(0).getColumnName()+" = "+valuesList.get(0).getValue();updateSQLs.add(sql);}}

除了断言还可以像上面一样根据 changes 取出所有变化的数据信息并拼成 sql。大家可以根据自己的需要取得这些信息。例如在自动化中 hack 一些信息。假如像我一样,拼出所有变化数据的 sql。这样在某些特定的 case,例如会影响其他 case 运行的一些场景。在 case 运行后自动拼出 sql 把数据恢复回去。 或者在有些自动化中你是获取不到一些信息的情况,例如后台发生了一些操作,而你并不知道或者不容易获取这些操作信息。就可以使用 changes 把这些信息都取出来,甚至根据需要 hack 一些东西。有兴趣的同学可以翻我之前写的监控式数据管理的帖子,看看我是怎么用 changes 做数据恢复的

Table

一直没说 table 的事。给个例子把,我几乎不怎么用。

Source source = new Source("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", "user", "password");Table table = new Table(source, "members");assertThat(table).column("name").hasValues("Hewson", "Evans", "Clayton", "Mullen");

Source

在 assertJ-db 中,无论是 changes,request 还是 table 等等。初始化的时候都是要传递一个 Source 作为参数的。其实就是你要传递一个数据的 datasouce 给 assertJ-db。 其实在 assertJ-db 中内置了一个 source,你可以看到如下的调用

Source source = new Source("jdbc:mysql://172.27.1.219:3306/dango?useUnicode=yes&amp;characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull", "write", "!@#$1234%^&*5678ABCDabcd");
Changes changes = new Changes(source);

但是~注意了,但是 assertJ-db 内置的这种方式慢的要死。强烈不建议使用。 我是使用的 mybatis 的 datasource 搞的,因为我有些数据库操作是用 mybatis 搞的。

总结

好了,assertJ-db 科普帖到此结束。

 更多内容欢迎来到我的知识星球:
 

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

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

相关文章

安装 Fedora CoreOS 操作系统

首发日期 2024-06-16, 以下为原文内容: 有一台吃灰几年的 e5-26v3 古老机器, 最近翻出来用一下. 首先从安装操作系统开始. 目录 1 FCOS 简介2 安装过程 2.1 下载 iso 镜像文件并制作安装 U 盘2.2 编写安装配置文件2.3 编译安装配置文件2.4 从 U 盘启动并安装 3 SSH 连接并测试…

直播平台美颜技术分析:视频美颜SDK功能实现原理

本篇文章&#xff0c;笔者将深入分析视频美颜SDK的功能实现原理&#xff0c;探讨其在直播平台中的应用。 一、视频美颜技术概述 通过这些功能&#xff0c;用户可以在直播过程中呈现更加理想的自己&#xff0c;从而提高观众的观看体验和互动积极性。 二、视频美颜SDK的功能 1…

不“卷”低价,品牌如何让客户愿意“留下”?

天猫取消预售制度&#xff0c;满减力度大于往年&#xff0c;京东直接将“又便宜又好”定为大促主题。今年的618&#xff0c;离不开两大关键词&#xff1a;拼低价 和 回归用户。 价格“内卷”&#xff0c;消费者可以花更少的钱买到商品&#xff0c;但对商家来说&#xff0c;意味…

6月19日(周三)A股行情总结:A股震荡收跌,恒生科技指数大涨3%,10年期国债期货转涨续创新高

内容提要 车路云概念延续昨日涨势&#xff0c;华铭智能20CM 3连板。贵金属及PEEK材料概念全日走强&#xff1b;港股有色金属及能源股走强&#xff0c;紫金矿业涨超3%&#xff0c;中石油涨超3%。国债期货午后全线转涨&#xff0c;10年期主力合约涨0.05%报104.925元&#xff0c;…

6.17继承

面向对象的特征&#xff1a;封装&#xff0c;继承&#xff0c;多态 使用背景&#xff1a;比如说在动物类底下可以有带毛的动物&#xff0c;带毛的动物符合所有的动物的特征&#xff0c;只是在这个基础上再继续添加一些特征 命名&#xff1a;原有类型称为“基类”或“父类”&a…

计算机网络(1) OSI七层模型与TCP/IP四层模型

一.OSI七层模型 OSI 七层模型是国际标准化组织ISO提出的一个网络分层模型&#xff0c;它的目的是使各种不同的计算机和网络在世界范围内按照相同的标准框架实现互联。OSI 模型把网络通信的工作分为 7 层&#xff0c;从下到上分别是物理层、数据链路层、网络层、传输层、会话层、…

类加载器、反射、注解

1、类加载器 1.1类加载器作用 负责将.class文件&#xff08;存储的物理文件&#xff09;加载在到内存中。 1.2类加载的过程 类加载时机 创建类的实例&#xff08;对象&#xff09;调用类的类方法访问类或者接口的类变量&#xff0c;或者为该类变量赋值使用反射方式来强制创建…

Java学习 (一) 环境安装及入门程序

一、安装java环境 1、获取软件包 https://www.oracle.com/java/technologies/downloads/ .exe 文件一路装过去就行&#xff0c;最好别装c盘 &#xff0c;我这里演示的时候是云主机只有C盘 2、配置环境变量 我的电脑--右键属性--高级系统设置--环境变量 在环境变量中添加如下配…

数字孪生涉及到的9大技术栈,都是难啃骨头呀。

数字孪生涉及到多个技术栈&#xff0c;包括但不限于以下几个方面&#xff1a; 数据采集和传感器技术&#xff1a; 数字孪生需要实时获取物理世界的数据&#xff0c;因此需要使用各种传感器技术&#xff08;如温度传感器、压力传感器、运动传感器等&#xff09;来采集数据&…

【猫狗分类】Pytorch VGG16 实现猫狗分类1-数据清洗+制作标签文件

Pytorch 猫狗分类 用Pytorch框架&#xff0c;实现分类问题&#xff0c;好像是学习了一些基础知识后的一个小项目阶段&#xff0c;通过这个分类问题&#xff0c;可以知道整个pytorch的工作流程是什么&#xff0c;会了一个分类&#xff0c;那就可以解决其他的分类问题&#xff0…

第6章 设备驱动程序(3)

目录 6.5 块设备操作 6.5.1 块设备的表示 6.5.2 数据结构 6.5.3 向系统添加磁盘和分区 6.5.4 打开块设备文件 本专栏文章将有70篇左右&#xff0c;欢迎关注&#xff0c;查看后续文章。 6.5 块设备操作 特点&#xff1a; 随机访问任意位置。 固定块大小的传输。 块设备在内…

手机网站制作软件是哪些

手机网站制作软件是一种用于设计、开发和创建适用于移动设备的网站的软件工具。随着移动互联网时代的到来&#xff0c;越来越多的用户开始使用手机浏览网页和进行在线交流&#xff0c;因此&#xff0c;手机网站制作软件也逐渐成为了市场上的热门工具。 1. Adobe Dreamweaver&am…

天翼云8080、80端口用不了的问题

天翼云8080、80端口用不了的问题 前言&#xff1a;前段时间天翼云搞了活动&#xff0c;原来公司用的华为云老板说太贵了也快到期了&#xff0c;就换了天翼云的服务器。 排查&#xff1a; 安全组开放 80 8080 防火墙查看 没有问题 nginx nacos dcoker等停了 查看监听端口 发现…

YOLOv10改进 | 注意力篇 | YOLOv10引入HAttention(HAT)注意力

1. HAT介绍 1.1 摘要:基于 Transformer 的方法在低级视觉任务(例如图像超分辨率)中表现出了令人印象深刻的性能。 然而,我们发现这些网络通过归因分析只能利用有限的输入信息空间范围。 这意味着 Transformer 的潜力在现有网络中仍未得到充分发挥。 为了激活更多的输入像素…

国际现货黄金的交易方式:二次入场机会识别

近期受地缘局势以及通胀因素的影响&#xff0c;国际现货黄金投资又重新受到市场的青睐。虽然近期金价出现大跌&#xff0c;但投资者反而认为这是低价买金的好机会。为了方便投资者做出决策&#xff0c;下面我们就介绍一些国际现货黄金的交易方式——二次入场点进场。 在国际现货…

探索高效和轻量级多模态大语言模型的奥秘

过去一年&#xff0c;多模态大语言模型(MLLM)在视觉问答、视觉理解和推理等任务中表现出色。然而&#xff0c;模型的庞大尺寸和训练推理的高成本限制了其在学术界和工业界的广泛应用。因此&#xff0c;研究高效和轻量级的MLLM具有重要意义&#xff0c;尤其是在边缘计算场景中。…

Graphviz——实现动态更新协议状态机

1、描述 为了实现动态更新协议状态机&#xff0c;首先需要定义类来表示协议状态机。初始化该类后&#xff0c;保存状态机对象。在后续更新过程中&#xff0c;就可以加载保存的状态机对象&#xff0c;添加新的状态或事件。Graphviz的安装过程参考&#xff1a;Graphviz——安装、…

ECharts 雷达图案例002 - 诈骗性质分析

ECharts 雷达图案例002 - 诈骗性质分析 &#x1f4ca; ECharts 雷达图案例002 - 诈骗性质分析 深入挖掘数据背后的故事&#xff0c;用可视化手段揭示诈骗行为的模式和趋势。 &#x1f50d; 案例亮点 创新的数据展示方式&#xff0c;让复杂的诈骗数据一目了然。定制化的雷达图…

一文带你入门【论文排版】利器·LaTeX |Macos

小罗碎碎念 我在刚开始写公众号的时候&#xff0c;写过一期推文&#xff0c;详细的讲解过如何使用LaTeX快速的进行论文排版。不过当时用的是windows的系统&#xff0c;这一次把Mac端的教程补上。 windows系统教程 https://zhuanlan.zhihu.com/p/677481269 LaTeX是一种流行的排…

Python10 python多线程

1.什么是python多线程 Python的多线程指的是在一个Python程序中同时运行多个线程&#xff0c;以达到并发执行多个任务的目的。线程是操作系统能够进行运算调度的最小单位&#xff0c;它被包含在进程之中&#xff0c;是进程中的实际运作单位。 在Python中&#xff0c;多线程的…