当前位置: 首页 > article >正文

go每日一题:mock打桩、defer、recovery、panic的调用顺序

题目一:单元测试中使用—打桩

  • 打桩概念:使用A替换 原函数B,那么A就是打桩函数
  • 打桩原理:运行时,通过一个包,将内存中函数的地址替换为桩函数的地址
  • 打桩操作:利用Patch()函数,将调用外部依赖等函数(数据库等依赖函数),替换为自己写的函数,这样就是实现了不对外部数据的一个强依赖
  • 最简单的用法,官方解释:Monkey’s API is very simple and straightfoward. Call monkey.Patch(, ) to replace a function. For example:
package main

import (
	"fmt"
	"os"
	"strings"

	"bou.ke/monkey"
)

func main() {
	monkey.Patch(fmt.Println, func(a ...interface{}) (n int, err error) {
		s := make([]interface{}, len(a))
		for i, v := range a {
			s[i] = strings.Replace(fmt.Sprint(v), "hell", "*bleep*", -1)
		}
		return fmt.Fprintln(os.Stdout, s...)
	})
	fmt.Println("what the hell?") // what the *bleep*?
}

下面是对一个io文件的mock示例,文件为外部依赖,存在不稳定性质,因此使用mock

package test

import (
        "bou.ke/monkey"
        "bufio"
        "github.com/stretchr/testify/assert"
        "os"
        "strings"
        "testing"
)

func readFirstLine() string {
        open, err := os.Open("file.txt")
        defer open.Close()
        if err != nil {
                return ""
        }

        scanner := bufio.NewScanner(open)
        for scanner.Scan() {
                return scanner.Text()
        }
        return ""
}

func replaceLine() string {
        line := readFirstLine()
        afterReplace := strings.ReplaceAll(line, "11", "00")
        return afterReplace
}

func TestReplace(t *testing.T) {
        monkey.Patch(readFirstLine, func() string {  //注意是readFirstLine函数名,而不是readFirstLine()
                return "line11"
        })
        defer monkey.Unpatch(readFirstLine) // 注意是readFirstLine函数名,而不是readFirstLine()
        res := replaceLine()
        assert.Equal(t, "line00", res)
}

题二:defer、recovery、panic执行顺序

  • 准则:panic当前函数的下一行代码不会被执行到
  • 当 panic 被触发后,Go 语言的运行时机制会开始查找当前函数以及调用栈上的所有 defer 函数,然后依次执行它们。
  • 在这个过程中,如果某个 defer 函数中使用了 recover 函数,那么 recover 就可以捕获到之前触发的 panic 异常,恢复程序的正常执行流程从引发 panic 的函数返回,继续执行后续代码,注意是直接在panic那里return,panic当前函数的下面的代码依然不会被执行,但是其他后续代码可以执行
  • 并且 recover 会返回 panic 时传递的参数(在这里就是 “触发一个异常” 这个字符串),可以在 defer 函数中根据返回值进行相应的处理,比如打印异常信息等。
package main

import "fmt"

func inner() {
    defer func() {
        if r := recover(); r!= nil {
            fmt.Printf("inner函数中的defer通过recover捕获到异常,异常信息: %v\n", r)
        }
    }()
    panic("inner函数中触发异常")
    defer fmt.Println("这一行代码直接不会被执行")
}

func outer() {
    defer func() {
        fmt.Println("outer函数中的defer执行了")
    }()
    inner()
}

func main() {
    fmt.Println("程序开始执行")
    outer()  //其中发生了panic,如果没有recovery,下面的代码将不再执行
    fmt.Println("outer函数调用结束后,继续执行main函数后面的代码")
}

http://www.kler.cn/a/415811.html

相关文章:

  • 单细胞细胞通讯全流程分析教程,代做分析和辅导
  • 0基础学前端系列 -- 深入理解 HTML 布局
  • React第十节组件之间传值之context
  • 【天地图】HTML页面实现车辆轨迹、起始点标记和轨迹打点的完整功能
  • 从0在自己机器上部署AlphaFold 3
  • A050-基于spring boot物流管理系统设计与实现
  • 【Linux】进程控制-----进程等待wait与waitpid
  • 用Go语言重写Linux系统命令 -- ping
  • Python读取摄像头视频并将其保存为MP4文件
  • 利用Java爬虫获得店铺详情:技术解析
  • KUKA机器人中断编程5—自动回原点功能的编程
  • 工程企业如何做好成本控制?该如何入手?
  • 和鲸科技创始人CEO范向伟出席首届工业智算产业发展研讨会,共话 AI 创新与产业化落地
  • 在windows系统中安装python并确认安装成功
  • 中信建投张青:以金融智慧点亮公益新篇章
  • Flink的双流join理解
  • 一次完整的CNAS软件测试实验室内部审核流程
  • Ubuntu-20.04安装 terminator
  • Spring Boot教程之十二: Spring – RestTemplate
  • [巅峰极客 2021]签到
  • 如何具体实现商品详情的提取?
  • 等保测评在云计算方面的应用讲解
  • 从覆盖到拼接:优化 onInput 事件的输入
  • uniapp开发微信小程序笔记8-uniapp使用vant框架
  • 3.26线性回归对率回归
  • 家校通小程序实战教程02口令管理