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

这篇具有很好参考价值的文章主要介绍了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 dao

import (
	"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 = now
	u.Ctime = now
	err := dao.db.WithContext(ctx).Create(&u).Error
	if mysqlErr, ok := err.(*mysql.MySQLError); ok {
		const uniqueConflictsErrNo uint16 = 1062
		if 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 *string
	Phone sql.NullString `gorm:"unique"`

	Birthday sql.NullInt64
	// 昵称
	Nickname sql.NullString
	// 自我介绍
	AboutMe       sql.NullString `gorm:"type=varchar(1024)"`
	WechatUnionID sql.NullString
	WechatOpenID  sql.NullString `gorm:"unique"`

	// 创建时间
	Ctime int64
	// 更新时间
	Utime int64
}

接着我们用编写测试用例

package dao

import (
	"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,不是 gomock
		mock func(t *testing.T) *sql.DB

		ctx  context.Context
		user User

		wantErr 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 不需要 ping
				DisableAutomaticPing: true,
				// 这个是什么呢?
				SkipDefaultTransaction: true,
			})
			d := NewUserDAO(db)
			u := tc.user
			err = 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 不会在初始化的过程中发起额外的调用。

Go 单元测试之Mysql数据库集成测试文章来源地址https://www.toymoban.com/news/detail-854828.html

到了这里,关于Go 单元测试之Mysql数据库集成测试的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • java 单元测试创建到测试(直接连接数据库方法)

    java 单元测试创建到测试(直接连接数据库方法)

    一.JUnit5常用注解 @Before注解用于在测试方法执行之前执行一次,可以用来设置测试环境、准备数据等。 @After注解用于在测试方法执行之后执行一次,可以用来清理测试环境、处理异常等。 @Test 表示方法是测试方法。他的职责非常单一不能生命任何属性,拓展的测试将会有

    2024年02月06日
    浏览(7)
  • java单元测试(二)H2数据库篇

    java单元测试(二)H2数据库篇

    H2 数据库是一个用 Java 开发的嵌入式(内存级别)数据库,它本身只是一个类库,也就是只有一个 jar 文件,可以直接嵌入到项目中。 H2数据库又被称为内存数据库,因为它支持在内存中创建数据库。 为什么测试数据库CRUD 对于Spring项目,特别是测试Service层或者dao层的代码时。需要验

    2024年02月06日
    浏览(13)
  • Go语言操作MySql数据库

    Go语言操作MySql数据库

           go-sql-driver/mysql库是Go语言官方推荐的MySQL驱动库,可以很方便地实现对MySQL数据库的连接和操作。本文记录一下使用go-sql-driver/mysql数据库驱动来操作mysql数据库。 目录 1.安装驱动程序 2.导入驱动包 3.操作数据库 3.1 获取mysql版本 3.2 创建表 3.3 表中插入数据 3.4 表中删除

    2024年02月07日
    浏览(13)
  • Go 语言实现 MySQL 数据库事务

    MySQL事务是指一组数据库操作,它们被视为一个逻辑单元,并且要么全部成功执行,要么全部回滚(撤销)。事务是数据库管理系统提供的一种机制,用于确保数据的一致性和完整性。 事务具有以下特性(通常由ACID原则定义): 原子性(Atomicity):事务中的所有操作要么全

    2024年02月08日
    浏览(11)
  • GO框架基础 (一)、MySQL数据库

    GO框架基础 (一)、MySQL数据库

    什么是数据库 数据库是一个组织化的数据集合,它被设计为方便存储、管理和检索数据。数据库通常以表格的形式组织数据,其中每一行代表一个数据记录,每一列代表一个数据字段。数据库系统提供了一种结构化的方法来存储和管理数据,以便用户可以有效地访问和操作数

    2024年02月20日
    浏览(9)
  • Go单元测试与集成测试:编写可靠的Go测试用例

    Go语言是一种现代编程语言,它具有简洁的语法、强大的性能和易于使用的并发特性。随着Go语言的发展和广泛应用,编写高质量的测试用例变得越来越重要。在Go语言中,我们可以使用内置的testing包来编写单元测试和集成测试。本文将涵盖Go单元测试与集成测试的核心概念、

    2024年02月19日
    浏览(9)
  • SpringBoot 如何使用 EmbeddedDatabaseBuilder 进行数据库集成测试

    SpringBoot 如何使用 EmbeddedDatabaseBuilder 进行数据库集成测试

    在开发 SpringBoot 应用程序时,我们通常需要与数据库进行交互。为了确保我们的应用程序在生产环境中可以正常工作,我们需要进行数据库集成测试,以测试我们的应用程序是否能够正确地与数据库交互。在本文中,我们将介绍如何使用 SpringBoot 中的 EmbeddedDatabaseBuilder 来进行

    2024年02月16日
    浏览(13)
  • go api(get post传参,数据库,redis) 测试

    go api(get post传参,数据库,redis) 测试

    介绍:分别测试get请求,post请求,请求链接数据库,以及redis操作。 1.api代码 2.相关sql 3.测试 3.1 get 3.2 post 这里面包括了测试redis 4.完整代码 项目地址

    2024年01月25日
    浏览(7)
  • mac系统之集成环境phpwebstudy初始化mysql数据库

    mac系统之集成环境phpwebstudy初始化mysql数据库

    PhpWebStudy是使用electron开发的桌面应用.目前支持的软件, nginx, apache, mysql, mariaDB, php, memcached, redis, mongoDB. 安装和卸载, 全部都是通过调用homebrew和macports的内置功能. 事实上, 使用homebrew或macports自行安装卸载和在软件里操作是一样的.对于习惯使用brew或port命令的用户, 依然可以继

    2024年02月01日
    浏览(14)
  • 【REST2SQL】07 GO 操作 Mysql 数据库

    【REST2SQL】07 GO 操作 Mysql 数据库

    【REST2SQL】01RDB关系型数据库REST初设计 【REST2SQL】02 GO连接Oracle数据库 【REST2SQL】03 GO读取JSON文件 【REST2SQL】04 REST2SQL第一版Oracle版实现 【REST2SQL】05 GO 操作 达梦 数据库 【REST2SQL】06 GO 跨包接口重构代码 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle旗

    2024年01月22日
    浏览(9)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包