前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go测试框架-Mock http请求

Go测试框架-Mock http请求

原创
作者头像
Johns
修改2022-06-30 10:26:06
2.7K0
修改2022-06-30 10:26:06
举报
文章被收录于专栏:代码工具代码工具

一. 使用httptest来mock一些http的服务

1.1 背景说明

最近做了一个营销活动,开发礼包领取功能时依赖了外部的系统发放点券,已知点券发放接口是非常稳定ok的了,目前这个接口仅可以在生产被调用。为了测试礼包领取功能,需要mock掉依赖的外部点券发放接口。

1.2 操作实践

代码语言:txt
复制
// 这是配置文件里面的,为了演示这里写死
// RemoteGamePointsApi 点券api地址
var RemoteGamePointsApi = "/gift_pack"

// RemoteGamePointsServiceAddress 点券服务地址
var RemoteGamePointsServiceAddress = ""

// GiftPackResp 外部点券发放接口响应
type GiftPackResp struct {
	QQ         string
	GamePoints int64
}

// GiftPackGet 礼包领取功能
func GiftPackGet(qq string) error {
	// step1. 参数校验

	// step2. 检查用户是否在本次活动黑名单 ...

	// step3.检查用户是否已经领取过了 ...

	// step4. 锁定当前账号, 防止同一个时刻同一个账号同时发放  ...

	// step5. 调用点券发放接口
	return sendGamePoints(qq)
}

// SendGamePoints 调用外部接口发送游戏点券
func sendGamePoints(qq string) error {
	if !qqValidator(qq) {
		return errors.New("qq is invalid")
	}

	// 发送点券
	resp, err := http.Get(fmt.Sprintf("%s/%s?qq=%s", RemoteGamePointsServiceAddress, RemoteGamePointsApi, qq))
	defer resp.Body.Close()

	// 解析响应结果
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	ret := GiftPackResp{}
	err = json.Unmarshal(bs, &ret)
	if err != nil {
		return err
	}
	fmt.Println(ret)
	return err

}

// qq 合法性校验
func qqValidator(qq string) bool {
	reg := regexp.MustCompile(`^[1-9]\d{3,10}$`)
	return reg.MatchString(qq)
}

// Test_GiftPackGet 测试礼包发放接口
func Test_GiftPackGet(t *testing.T) {
	Convey("test utils GiftPackGet", t, func() {
		Convey("When request use httptest mock remote api", func() {
			ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				if r.Method != http.MethodGet {
					w.WriteHeader(http.StatusNotFound)
				}
				if r.URL.EscapedPath() != RemoteGamePointsApi {
					w.WriteHeader(http.StatusNotFound)
				}
				qq := r.URL.Query().Get("qq")
				w.WriteHeader(http.StatusOK)
				g := GiftPackResp{qq, 100}
				bs, _ := json.Marshal(g)
				w.Write(bs)
			}))

			defer ts.Close()
			RemoteGamePointsServiceAddress = ts.URL
			err := GiftPackGet("3095764312")
			So(err, ShouldBeNil)
		})
	})
}

代码解释:

  • GiftPackGet 是对外的礼包发放接口,在调用前需要做一些活动规则的检查
  • sendGamePoints 是调用的外部的点券发送接口api,调用会返回点券发送的回执
  • 通过mock掉点券发送接口api, 我们可以将测试聚焦在具体的活动规则检查上,这部分才是我们自己的业务逻辑,是我们需要重点测试的部分。

二. 关于mock的思考

关于mock一直都是一个讨论比较激烈的点:

一方的人主张不要滥用mock,能不mock就不mock。被测单元也不一定是具体的一个函数,可能是多个函数本来就应该串起来,必要的时候再mock。

一方则主张将被测函数所有调用的外面函数全部mock掉,只关注被测函数自己的一行行代码,只要调用其他函数,全都mock掉,用假数据来测试。

个人感觉用不用mock就是一个选择问题,需要具体问题具体看待。如果依赖的模块自己可控, 那么我宁愿用测试数据保证上下依赖ok,专注到被测试的模块。

三. 什么时候适合mock?

  • 该对象提供非确定的结果(比如当前的时间或者当前的温度)。
  • 对象的某些状态难以创建或者重现(比如网络错误或者文件读写错误)。
  • 对象方法上的执行太慢(比如在测试开始之前初始化数据库)。
  • 该对象还不存在或者其行为可能发生变化(比如测试驱动开发中驱动创建新的类)。
  • 该对象必须包含一些专门为测试准备的数据或者方法。
  • 外部的一些调用代价较高的接口(例如调用一次100元的接口)。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一. 使用httptest来mock一些http的服务
    • 1.1 背景说明
      • 1.2 操作实践
      • 二. 关于mock的思考
      • 三. 什么时候适合mock?
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档