Go 单元测试之Mysql数据库集成测试

文章目录

    • 一、 sqlmock介绍
    • 二、安装
    • 三、基本用法
    • 四、一个小案例
    • 五、Gorm 初始化注意点

一、 sqlmock介绍

sqlmock 是一个用于测试数据库交互的 Go 模拟库。它可以模拟 SQL 查询、插入、更新等操作,并且可以验证 SQL 语句的执行情况,非常适合用于单元测试中。

二、安装

go get github.com/DATA-DOG/go-sqlmock

三、基本用法

使用 sqlmock 进行 MySQL 数据库集成测试的基本步骤如下:

  1. 创建模拟 DB 连接:
import ("database/sql""testing""github.com/DATA-DOG/go-sqlmock"
)func TestMyDBFunction(t *testing.T) {db, mock, err := sqlmock.New()if err != nil {t.Fatalf("Error creating mock database: %v", err)}defer db.Close()// 使用 mock 来替代真实的数据库连接// db 可以传递给被测试的函数进行测试
}
  1. 设置模拟 SQL 查询和预期结果:
// 模拟 SQL 查询并设置预期结果
rows := sqlmock.NewRows([]string{"id", "name"}).AddRow(1, "Alice").AddRow(2, "Bob")
mock.ExpectQuery("SELECT id, name FROM users").WillReturnRows(rows)
  1. 调用被测试的函数,并传入模拟的数据库连接:
// 调用被测试的函数,传入模拟的数据库连接
result := MyDBFunction(db)// 验证结果是否符合预期
if result != expected {t.Errorf("Expected %d, got %d", expected, result)
}

四、一个小案例

这里我们定义了一个 GORMUserDAO 结构体,它实现了 UserDAO 接口,用于与用户表进行交互。这个结构体通过 gorm.DB 实例与数据库进行通信。

具体来说,GORMUserDAO 提供了 Insert 方法,用于在数据库中创建新用户。这个方法接受一个 User 类型的结构体作为参数,该结构体定义了用户的基本信息,包括 ID、邮箱、密码、手机号、生日、昵称、自我介绍、微信 UnionID 和 OpenID 等字段。

Insert 方法中,首先获取当前时间戳(以毫秒为单位),并设置用户的创建时间和更新时间。然后,使用 gorm.DBCreate 方法将用户信息插入到数据库中。如果插入操作遇到唯一性约束错误(例如邮箱或手机号已存在),方法会返回一个特定的错误 ErrUserDuplicate

User 结构体定义了数据库表的结构,其中包含了一些列的定义,如 EmailPhone 被设置为唯一索引。此外,还定义了一些列的类型和约束,如 AboutMe 字段被设置为最大长度为 1024 的字符串类型。

提供了一个使用 GORM 进行数据库操作的 DAO 层,用于处理用户数据的创建。

// internal/user/dao/user.go
package daoimport ("context""database/sql""errors""github.com/go-sql-driver/mysql""gorm.io/gorm""time"
)var (ErrUserDuplicate = errors.New("邮箱冲突")
)type UserDAO interface {Insert(ctx context.Context, u User) error
}type GORMUserDAO struct {db *gorm.DB
}func NewUserDAO(db *gorm.DB) UserDAO {return &GORMUserDAO{db: db,}
}func (dao *GORMUserDAO) Insert(ctx context.Context, u User) error {// 存毫秒数now := time.Now().UnixMilli()u.Utime = nowu.Ctime = nowerr := dao.db.WithContext(ctx).Create(&u).Errorif mysqlErr, ok := err.(*mysql.MySQLError); ok {const uniqueConflictsErrNo uint16 = 1062if mysqlErr.Number == uniqueConflictsErrNo {// 邮箱冲突 or 手机号码冲突return ErrUserDuplicate}}return err
}// User 直接对应数据库表结构
// 有些人叫做 entity,有些人叫做 model,有些人叫做 PO(persistent object)
type User struct {Id int64 `gorm:"primaryKey,autoIncrement"`// 设置为唯一索引Email    sql.NullString `gorm:"unique"`Password string//Phone *stringPhone sql.NullString `gorm:"unique"`Birthday sql.NullInt64// 昵称Nickname sql.NullString// 自我介绍AboutMe       sql.NullString `gorm:"type=varchar(1024)"`WechatUnionID sql.NullStringWechatOpenID  sql.NullString `gorm:"unique"`// 创建时间Ctime int64// 更新时间Utime int64
}

接着我们用编写测试用例

package daoimport ("context""database/sql""errors""github.com/DATA-DOG/go-sqlmock""github.com/go-sql-driver/mysql""github.com/stretchr/testify/assert""github.com/stretchr/testify/require"gormMysql "gorm.io/driver/mysql""gorm.io/gorm""testing"
)func TestGORMUserDAO_Insert(t *testing.T) {//testCases := []struct {name string// 为什么不用 ctrl ?// 因为你这里是 sqlmock,不是 gomockmock func(t *testing.T) *sql.DBctx  context.Contextuser UserwantErr error}{{name: "插入成功",mock: func(t *testing.T) *sql.DB {mockDB, mock, err := sqlmock.New()res := sqlmock.NewResult(3, 1)// 这边预期的是正则表达式// 这个写法的意思就是,只要是 INSERT 到 users 的语句mock.ExpectExec("INSERT INTO `users` .*").WillReturnResult(res)require.NoError(t, err)return mockDB},user: User{Email: sql.NullString{String: "123@qq.com",Valid:  true,},},},{name: "邮箱冲突",mock: func(t *testing.T) *sql.DB {mockDB, mock, err := sqlmock.New()// 这边预期的是正则表达式// 这个写法的意思就是,只要是 INSERT 到 users 的语句mock.ExpectExec("INSERT INTO `users` .*").WillReturnError(&mysql.MySQLError{Number: 1062,})require.NoError(t, err)return mockDB},user:    User{},wantErr: ErrUserDuplicate,},{name: "数据库错误",mock: func(t *testing.T) *sql.DB {mockDB, mock, err := sqlmock.New()// 这边预期的是正则表达式// 这个写法的意思就是,只要是 INSERT 到 users 的语句mock.ExpectExec("INSERT INTO `users` .*").WillReturnError(errors.New("数据库错误"))require.NoError(t, err)return mockDB},user:    User{},wantErr: errors.New("数据库错误"),},}for _, tc := range testCases {t.Run(tc.name, func(t *testing.T) {db, err := gorm.Open(gormMysql.New(gormMysql.Config{Conn: tc.mock(t),// SELECT VERSION;SkipInitializeWithVersion: true,}), &gorm.Config{// 你 mock DB 不需要 pingDisableAutomaticPing: true,// 这个是什么呢?SkipDefaultTransaction: true,})d := NewUserDAO(db)u := tc.usererr = d.Insert(tc.ctx, u)assert.Equal(t, tc.wantErr, err)})}
}

五、Gorm 初始化注意点

这里运行测试的代码也有点与众不同,在初始化 GORM 的时候需要额外设置三个参数。

  • SkipInitializeWithVersion:如果为 false,那么 GORM 在初始化的时候,会先调用 show version
  • DisableAutomiticPing:为 true 不允许 Ping 数据库。
  • SkipDefaultTransaction:为 false 的时候,即便是一个单一增删改语句,GORM 也会开启事务。

这三个选项禁用之后,就可以确保 GORM 不会在初始化的过程中发起额外的调用。

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

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

相关文章

如何安装MacOS的虚拟机?mac安装虚拟机的步骤 虚拟机安装MacOS VMware Fusion和Parallels Desktop19

要在Mac上运行MacOS的虚拟机,常用的方法是使用虚拟化软件如VMware Fusion或Parallels Desktop。 以下是安装MacOS的虚拟机的主要步骤: 1. 检查系统要求:确定您的Mac硬件和操作系统满足安装要求。您需要一台具备足够性能的Mac,并…

【前端Vue】Vue从0基础完整教程第7篇:组件化开发,组件通信【附代码文档】

Vue从0基础到大神学习完整教程完整教程(附代码资料)主要内容讲述:vue基本概念,vue-cli的使用,vue的插值表达式,{{ gaga }},{{ if (obj.age > 18 ) { } }},vue指令,综合…

GPT国内怎么用?4月最新版本来了

ChatGPT镜像 今天在知乎看到一个问题:“平民不参与内测的话没有账号还有机会使用ChatGPT吗?” 从去年GPT大火到现在,关于GPT的消息铺天盖地,真要有心想要去用,途径很多,别的不说,国内GPT的镜像…

37、Tomato(VulnHub)

Tomato 一、nmap 2211是ssh的端口,21的ftp也不是弱密码 二、web渗透 随便看看 目录爆破 /seclists/Discovery/Web-Content/common.txt /antibot_image/antibots/readme.txt 发现该站点存在反爬机制 /antibot_image/antibots/info.php 提示我们该网页存在个参数 GET&…

FineBI 6.0 Linux 部署、ClickHouse 源配置

文章目录 FineBI 概述FineBI 部署安装环境说明1.下载安装包2.安装3.初始化设置4.登录5.快速入门 启动与关闭启动关闭 ClickHouse 源配置开启驱动上传功能驱动上传数据库连接配置基础表属性设置数据导入 FineBI 概述 FineBI 是一款国产的商业智能(BI)软件…

Quartz + SpringBoot 实现分布式定时任务

文章目录 前言一、分布式定时任务解决方案二、Quartz是什么?1.quartz简介2.quartz的优缺点 二、Quartz分布式部署总结 前言 因为应用升级,由之前的单节点微服务应用升级为集群微服务应用,所以之前的定时任务Spring Scheduled不再适用了&…

固定测斜仪:工程观测的精密利器

在工程观测测量领域,固定测斜仪扮演着至关重要的角色。固定测斜仪,凭借其耐冲击型倾斜传感器、出色的可靠性、快速稳定的特点,以及简洁的安装和智能识别功能,已成为行业内重要工具。其输出信号为RS485数字量,可直接显示…

Postman之全局变量与环境变量配置

实际开发中可能需要不停切换环境,接口中来回输入环境地址比较麻烦,故而通过定义变量来节约频繁更换测试地址所耗费的时间。Postman 允许定义自己的全局变量(Globals)与环境变量(Environment),最…

51-41 Stable Video Diffusion,高质量视频生成新时代

23年11月,Stability AI公司公开了稳定视频扩散模型Stable Video Diffusion(SVD)的代码和权重,视频生成迎来了新时代。SVD是一种潜在扩散模型,支持文本生成视频、图像生成视频以及物体多视角3D合成。从工程角度来看,本文主要提出了…

如何使用Postgres的扩展(如PostGIS)来支持地理空间数据

文章目录 解决方案1. 安装PostGIS扩展2. 创建地理空间数据表3. 插入地理空间数据4. 进行地理空间查询 示例代码 在PostgreSQL中,我们可以使用扩展来增强数据库的功能。对于地理空间数据,PostGIS是一个特别有用的扩展,它提供了对地理对象&…

Linux安装mysql 8.0

1.使用root登录服务器 2.创建安装包存放目录 # mkdir /software # cd /software3.下载并解压mysql安装包 # wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.21-linux-glibc2.12-x86_64.tar.xz # tar xvJf mysql-8.0.21-linux-glibc2.12-x86_64.tar.xz # mv m…

反激电源——TL431及光耦反馈电路计算(不涉及环路补偿)

一、TL431及光耦反馈电路 TL431以及光耦电路是反激的副边反馈类型电路中的常见应用。 其反馈工作原理为:当副边的输出电压升高时,TL431的REF点采样电压也会升高,使得TL431的导通量增加,同时光耦内部的发光二极管流过的电流也增大&…

利用动态规划优化10年投资回报:策略、证明与算法分析

利用动态规划优化10年投资回报:策略、证明与算法分析 a. 存在最优投资策略的证明b. 最优子结构性质的证明c. 最优投资策略规划算法设计d. 新限制条款下最优子结构性质的证明 在面对投资策略规划问题时,我们的目标是在10年后获得最大的回报。Amalgamated投…

产废端实时音视频监控系统在运输车辆驾驶室中的应用

实时音视频监控系统可通过在运输车辆驾驶室安装音视频摄录设备,实现将运输车辆内部及周围环境音视频数据通过移动网络实时回传指挥中心的功能。 前端摄录设备主要负责采集车内外的视音频信息,为了保障车辆及运输人员 的安全,应合理选择摄录设…

HTML5 <video> 标签属性、API 方法、事件、自定义样式详解与实用示例

HTML5 <video> 标签为网页内嵌视频提供了强大且便捷的功能。以下是对 <video> 标签的主要属性、API 方法、事件、自定义样式及其使用示例的详细介绍&#xff1a; 一、属性 1. src 定义&#xff1a;指定视频文件的 URL。示例&#xff1a;<video src"my_v…

linux-centos虚拟机设置固定ip

环境准备 虚拟机版本&#xff1a;centos7 安装环境&#xff1a;vmware17 1、设置网络连接 虚拟机-设置-网络适配器-NAT模式 2、查看子网信息 编辑-虚拟网络编辑器-NAT模式-NAT设置 查看子网ip和网关ip 下一步要用 3、修改配置文件 vim /etc/sysconfig/network-scripts…

接口压力测试 jmeter--入门篇(一)

一 压力测试的目的 评估系统的能力识别系统的弱点&#xff1a;瓶颈/弱点检查系统的隐藏的问题检验系统的稳定性和可靠性 二 性能测试指标以及测算 【虚拟用户数】&#xff1a;线程用户【并发数】&#xff1a;指在某一时间&#xff0c;一定数量的虚拟用户同时对系统的某个功…

Linux 搭建私有yum源仓库

一、环境准备 IP系统版本作用192.168.140.155CentOS 7.9.2009yum源仓库192.168.140.153CentOS 7.9.2009测试 准备两台服务器&#xff0c;一台作为yum源仓库&#xff0c;另一台作为测试使用。 二、搭建yum源服务器 &#xff08;无法连接外网的情况&#xff0c;需要去官网下载镜…

IP定位技术在解决广告恶意点击问题中的应用

随着互联网的迅猛发展&#xff0c;数字广告已成为企业推广产品和服务的重要方式。然而&#xff0c;随之而来的是广告恶意点击的问题&#xff0c;这不仅导致广告主的损失&#xff0c;也影响了广告生态的健康发展。为了解决这一问题&#xff0c;IP定位技术应运而生&#xff0c;成…

PACNet CellNet(代码开源)|bulk数据作细胞分类,评估细胞命运性能的一大利器

文章目录 1.前言2.CellNet2.1CellNet简介2.2CellNet结果 3.PACNet3.1安装R包与加载R包3.2加载数据3.3开始训练和分类3.4可视化分类过程3.5可视化分类结果 4.细胞命运分类和免疫浸润比较 1.前言 今天冲浪看到一个细胞分类性能评估的R包——PACNet&#xff0c;它与转录组分析方法…