Gone框架介绍19 -如何进行单元测试?

gone是可以高效开发Web服务的Golang依赖注入框架
github地址:https://github.com/gone-io/gone
文档地址:https://goner.fun/zh/
请帮忙在github上点个 ⭐️吧,这对我很重要 ;万分感谢!!

文章目录

  • 单元测试
    • 假设我们编写的Goner如下
    • 我们可以编写测试文件如下:
    • 使用gomock做mock测试

单元测试

在一个依赖注入框架中如何进行单元测试,将依赖项先注入后再测试;如果测试内容和注入内容强相关,可以考虑对相关内容做mock;一种方式是手动将mock后的Goner埋葬到系统,另外一种方式时将已经埋葬的Goner,使用cemetery.ReplaceBury做替换性埋葬。

假设我们编写的Goner如下

文件名:goner.go

package testimport ("github.com/gone-io/gone""github.com/gone-io/gone/goner/config"
)const pointNameA = "example-test-point-a"
const pointNameB = "example-test-point-b"func NewPointA() (gone.Goner, gone.GonerId) {return &Point{}, pointNameA
}func NewPointB() (gone.Goner, gone.GonerId) {return &Point{X: -1, Y: -1}, pointNameB
}type Point struct {gone.FlagX int `gone:"config,example.test.point.a-x"`Y int `gone:"config,example.test.point.a-y,default=200"`
}type Line struct {gone.FlagA *Point `gone:"example-test-point-a"`B *Point `gone:"example-test-point-b"`
}func (*Line) Say() string {return ""
}func NewLine() *Line {return &Line{}
}func Priest(cemetery gone.Cemetery) error {cemetery.Bury(NewPointA())cemetery.Bury(NewPointB())cemetery.Bury(NewLine())return config.Priest(cemetery)
}

我们可以编写测试文件如下:

文件名:goner_test.go

package testimport ("github.com/gone-io/gone""github.com/gone-io/gone/goner/config""github.com/stretchr/testify/assert""testing"
)func Test_Line(t *testing.T) {t.Run("config default", func(t *testing.T) {gone.TestAt(pointNameA, func(point *Point) {assert.Equal(t, point.X, 1000)assert.Equal(t, point.Y, 200)}, config.Priest, Priest)})t.Run("config default", func(t *testing.T) {gone.Test(func(line *Line) {assert.Equal(t, line.A.Y, 200)}, Priest)})t.Run("ReplaceBury", func(t *testing.T) {gone.Test(func(line *Line) {assert.Equal(t, line.A.X, 20)}, Priest, func(cemetery gone.Cemetery) error {Mock := func() gone.Goner {return &Point{X: 20}}return cemetery.ReplaceBury(Mock(), pointNameA)})})
}

使用gomock做mock测试

为了解耦,我们推荐使用接口进行注入;实际上推荐接口注入的另一个原因是,go语言提供了基于接口的mock方案,我们可以将依赖的内容都mock起来。然而使用mockgen生成的mock实现,不是Goner,无法被埋葬,所以也无法注入;为此,我们在辅助工具中提供了解决方案。

gone mock  -f ${fromGoFile} -o ${outGoFile}

gone mock 命令可以在一个mockgen生成的mock对象中增加gone.Flag,让其变成一个Goner,可以进入Cemetery。

一般的使用方法是,在需要mock的接口上加//go:generate注释,让生成过程在go generate ./...命令时自动完成,下面是一个例子:

文件名:i_point.go

package test//go:generate sh -c "mockgen -package=mock -source=$GOFILE|gone mock -o mock/$GOFILE"
type IPoint interface {GetX() intGetY() int
}

上面//go:generate sh -c "mockgen -package=mock -source=$GOFILE|gone mock -o mock/$GOFILE"的作用是,先用mock为该接口生成一个mock对象,然后通过管道传递给gone mock添加gone.Flag标记。

注意mockgen工具和gomock包的版本需要保持一致;
运行下面代码,安装最新版本:

go get github.com/golang/mock/gomock
go get github.com/golang/mock/mockgen

需要安装gone辅助工具;安装参考 gone辅助工具。

好让,我们来试试吧,创建一个空目录并在进入后,将上文件i_test.go创建出来,让后在当前目录运行命令:

go generate ./...

可以看到,命令运行完后,将生成文件mock/i_point.go

下面我们创建一个 origin_point.go文件,内容如下:

package testimport "github.com/gone-io/gone"type originPoint struct {gone.Flag
}//go:gone
func NewOriginPoint() gone.Goner {return &originPoint{}
}func (o *originPoint) GetX() int {return 100
}
func (o *originPoint) GetY() int {return 200
}

在创建一个名为distance_calculator.go的文件,内容如下:

package testimport ("github.com/gone-io/gone""math"
)//go:gone
func NewDistanceCalculator() gone.Goner {return &distanceCalculator{}
}type distanceCalculator struct {gone.FlagoriginPoint IPoint `gone:"*"`
}func (d *distanceCalculator) CalculateDistanceFromOrigin(x, y int) float64 {originX, originY := d.originPoint.GetX(), d.originPoint.GetY()return math.Sqrt(math.Pow(float64(x-originX), 2) + math.Pow(float64(y-originY), 2))
}

distanceCalculator 的业务是计算(x,y int)到originPoint点的距离,originPoint是依赖注入的;现在我们来编写CalculateDistanceFromOrigin的测试函数如下:

package testimport ("example/test/mock""github.com/golang/mock/gomock""github.com/gone-io/gone""github.com/stretchr/testify/assert""testing"
)func Test_distanceCalculator_CalculateDistanceFromOrigin(t *testing.T) {//创建mock控制器controller := gomock.NewController(t)defer controller.Finish()gone.Test(func(d *distanceCalculator) {distance := d.CalculateDistanceFromOrigin(3, 4)assert.Equal(t, float64(5), distance)}, func(cemetery gone.Cemetery) error {//创建mock对象point := mock.NewMockIPoint(controller)point.EXPECT().GetX().Return(0)point.EXPECT().GetY().Return(0)//将mock对象埋葬到Cemeterycemetery.Bury(point)//被测试的对象也需要埋葬到Cemeterycemetery.Bury(NewDistanceCalculator())return nil})
}

上一篇:Gone框架介绍18 - redis 分布式缓存 和 分布式锁

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

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

相关文章

CentOs安装

安装 开发工具 :GCC、 JDK、mysql 如果出现蓝屏,要在BIOS开启虚拟化支持,或者移除打印机。

Google:站长移除无效网址

当您的网址不需要呈现在Google站长中时,您可以在站长工具中移除网址 操作步骤:登录Google站长,绑定网站完成后,点击左侧删除 >> 输入网址 如果遇到一些网址,可以找寻网址间的规律,比如说&#xff0…

2024生日快乐祝福HTML源码

源码介绍 2024生日快乐祝福HTML源码,源码由HTMLCSSJS组成,记事本打开源码文件可以进行内容文字之类的修改,双击html文件可以本地运行效果,也可以上传到服务器里面, 源码截图 源码下载 2024生日快乐祝福HTML源码

Shell脚本 <<EOF ... EOF语法(Here Document)(特殊的输入重定向方式)(定界符)

文章目录 Here Document语法Here Document 的基本语法使用场景 关于定界符定界符不是变量定界符在 Here Document 中只是一个字符串,主要功能是标记输入文本的开始和结束,使用时应遵循最佳实践格式要求例子和说明如何使用定界符定界符可重复使用&#xf…

Spring数据访问全攻略:从JdbcTemplate到声明式事务

上文讲到 —— 航向数据之海:Spring的JPA与Hibernate秘籍 本文目录 四. JdbcTemplate的使用定义JdbcTemplate及其在Spring中的作用展示如何使用JdbcTemplate简化数据库操作1. 配置JdbcTemplate2. 使用JdbcTemplate查询数据3. 打印查询结果 五. Spring的事务管理介绍…

桥接模式

桥接模式:在这种模式下,虚拟机就像是局域网中一台独立的主机,能够访问网内任何一台机器。在桥接模式下,必须为虚拟系统手动配置IP地址、子网掩码,并且这些配置需要与宿主机器处于同一网段,以便虚拟系统和宿…

leetcode-42. 接雨水(双指针,前缀)

42. 接雨水 /*** param {number[]} height* return {number}*/ var trap function (height) {let len height.length;let pre_max new Array(len).fill(0);let suf_max new Array(len).fill(0);pre_max[0] height[0];suf_max[len - 1] height[len - 1];for (let i 1; i…

queue使用

C的queue是一种先进先出(FIFO)的数据结构,可以用来存储一系列元素。它属于STL(Standard Template Library)的一部分,以queue模板类的形式提供。 要使用queue,需要包含头文件,并使用…

Linux shell编程学习笔记49:strings命令

0 前言 在使用Linux的过程中,有时我们需要在obj文件或二进制文件中查找可打印的字符串,那么可以strings命令。 1. strings命令 的功能、格式和选项说明 我们可以使用命令 strings --help 来查看strings命令的帮助信息。 pupleEndurer bash ~ $ strin…

在k8s中搭建elasticsearch高可用集群,并对数据进行持久化存储

🐇明明跟你说过:个人主页 🏅个人专栏:《洞察之眼:ELK监控与可视化》🏅 🔖行路有良友,便是天堂🔖 目录 一、引言 1、Elasticsearch简介 2、k8s简介 二、环境准备 …

Git项目管理——提交项目和版本回退(二)

个人名片: 🎓作者简介:嵌入式领域优质创作者🌐个人主页:妄北y 📞个人QQ:2061314755 💌个人邮箱:[mailto:2061314755qq.com] 📱个人微信:Vir2025WB…

android绘制多个黑竖线条

本文实例为大家分享了android绘制多个黑竖线条展示的具体代码,供大家参考,具体内容如下 1.写一个LinearLayout的布局,将宽度写成5dp将高度写成match_parent. 2.在写一个类继承LinearLayout,用LayoutInflater实现子布局的在这个L…

train_gpt2_fp32.cu - main

llm.c/test_gpt2_fp32.cu at master karpathy/llm.c (github.com) 源码 // ---------------------------------------------------------------------------- // main training loop int main(int argc, char *argv[]) {// read in the (optional) command line argumentsco…

三.使用HashiCorp Vault工具管理数据库

三.ubuntu安装使用HashiCorp Vault工具管理数据库 HashiCorp Vault 是一个基于身份的秘密和加密管理系统。机密是您想要严格控制访问的任何内容,例如 API 加密密钥、密码和证书。Vault 提供由身份验证和授权方法门控的加密服务。使用 Vault 的 UI、CLI 或 HTTP API,可以安全…

深度优先搜索汇总

常用英文 最近公共祖先(Lowest Common Ancestor,简称LCA) posterity,英语单词,主要用作名词,作名词时译为“子孙,后裔;后代”。 什么是深度优先搜索 深度优先搜索,D…

[前端] vue2的/deep/转化为vue3语法(笔记)

vue2语法示例 <style scoped lang"less">/deep/.el-carousel__button {width: 8px;height: 3px;border-radius: 3px;}/deep/.el-carousel__indicator.is-active button {width: 16px;} } </style>在 Vue 3 中&#xff0c;/deep/ 或 >>> 选择器…

24 内核开发- Linux 内核各种设计模式

24 内核开发- Linux 内核各种设计模式 Linux 内核中使用了各种设计模式来组织和结构其庞大的代码库。以下是 Linux 内核中的一些常见设计模式&#xff1a; 1. 单例模式&#xff1a; 模块&#xff1a; init 模块 目的&#xff1a; 初始化内核并创建第一个进程 (init_task) 实现…

uni-app 实现下拉单选功能(六)

总体的设计思想是,一个输入框在客户点击时,弹出需要选择的下拉框选项,客户选择完后,隐藏下拉框选项内容;并将选择的数据填充到输入框内。话不多说直接上代码: <template> <view class="dianjianInfo"> <view class="uni-form…

文心一言指令

文心一言 文心一言&#xff08;ERNIE Bot&#xff09;是百度公司研发的知识增强大语言模型&#xff0c;它可以根据用户的指令和输入&#xff0c;生成相应的回答或文本。以下是一些可能的指令示例&#xff0c;用于指导文心一言完成不同的任务&#xff1a; 知识问答&#xff1a…

【oracle】图片转为字节、base64编码等形式批量插入oracle数据库并查询

1.熟悉、梳理、总结下Oracle相关知识体系 2.欢迎批评指正&#xff0c;跪谢一键三连&#xff01; 资源下载&#xff1a; oci.dll、oraocci11.dll、oraociei11.dll3个资源文件资源下载&#xff1a; Instant Client Setup.exe资源下载&#xff1a; oci.dll、oraocci11.dll、oraoc…