Go测试技术分享(一):场景化接口Case编写

 

 

一、前言

  本人负责的支付清结算方向的测试工作,在测试项目中,会出现流程化的接口调用,请求完一个接口后,继续请求另一个接口(这里的接口可以指Http,也指rpc接口),这里以一个真实场景为例:用户在平台下单,结算前部分退款,再结算,最后结算后部分退款;

  第一个接口动作对应用户下单,第二个动作对应结算前的部分退款,第三个动作对应结算,第四个动作对应结算后的部分退款,涉及不同系统的交互;这是一个完整的场景,根据我们的测试用例与更多的用户场景,实际测试中,我们需要测试更多场景,单接口测试已无法满足实际需求。

 

 

 

 

二、表格驱动测试

  我们可以定义一个结构体,将每一个步骤定义成一个节点,通过遍历节点达到执行整个流程的效果:

  优点就是代码更加清晰、明确,也便于调整步骤的顺序、新增或者移除某些步骤。另外,在循环体中增加调试日志也非常的简单;

  但还是有缺点的,看上去似乎不满足接口测试一些要求,没有case管理,无法做接口断言等  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
func main() {
 ctx := &context{}
 
 steps := []struct {
  name string
  fn   func() error
 }{
  {"parse flags", ctx.parseFlags},
  {"read schema", ctx.readSchema},
  {"dump schema", ctx.dumpSchema}, // Before transformations
  {"remove builtin constructors", ctx.removeBuiltinConstructors},
  {"add adhoc constructors", ctx.addAdhocConstructors},
  {"validate schema", ctx.validateSchema},
  {"decompose arrays", ctx.decomposeArrays},
  {"replace arrays", ctx.replaceArrays},
  {"resolve generics", ctx.resolveGenerics},
  {"dump schema", ctx.dumpSchema}, // After transformations
  {"decode combinators", ctx.decodeCombinators},
  {"dump decoded combinators", ctx.dumpDecodedCombinators},
  {"codegen", ctx.codegen},
 }
 
 for _, step := range steps {
  ctx.debugf("start %s step", step.name)
  if err := step.fn(); err != nil {
   log.Fatalf("%s: %v", step.name, err)
  }
 }
}

 

三、封装

将场景和节点定义成结构体,提供场景与节点独立的执行接口:

实际的节点,需要定义成这个结构体的方法;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
type SenceSuite struct {
    SenceSuite string
}
 
type Plan struct {
    Planname string
    Fn       func(map[string]interface{}) interface{}
    Data     map[string]interface{}
}
 
var SenceSuiteDao *SenceSuite
var SenceSuiteOnce sync.Once
 
func NewSenceSuiteDao() *SenceSuite {
    SenceSuiteOnce.Do(
        func() {
            SenceSuiteDao = &SenceSuite{}
        })
    return SenceSuiteDao
}
 
func (dao *SenceSuite) DoSence(steps []Plan) {
    for _, step := range steps {
        step.Fn(step.Data)
    }
}
 
func (dao *SenceSuite) DoPlan(step Plan) interface{} {
    return step.Fn(step.Data)
}

  

四、实际使用

接口case管理:"github.com/smartystreets/goconvey/convey"

这里仍然以上面的场景为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//结算前部分退款,再结算,部分退款
func TestRefundAndNomalSettleAndRefund(t *testing.T) {
   // 初始化数据库
    utils.DBInit()
        //用户下单
    order := GetOrder("ZFB", "SELF", "nrmol")
    env := "prod"
    way := "1"
    SenceSuite := utils.NewSenceSuiteDao()
    convey.Convey("结算前部分退款", t, func() {
        P1 := utils.Plan{Planname: "结算前部分退款", Fn: SenceSuite.Refund, Data: map[string]interface{}{}}
        res := SenceSuite.DoPlan(P1).(*xxx)
        convey.So(res.RetCode, convey.ShouldEqual, "000000")
    })
    convey.Convey("正常结算", t, func() {
        P2 := utils.Plan{Planname: "正常结算", Fn: SenceSuite.Settle, Data: map[string]interface{}{}}
        res := SenceSuite.DoPlan(P2).(*xxx)
        convey.So(res.RetCode, convey.ShouldEqual, "000000")
    })
    convey.Convey("结算后部分退款", t, func() {
        P3 := utils.Plan{Planname: "结算后部分退款", Fn: SenceSuite.Refund, Data: map[string]interface{}{}}
        res := SenceSuite.DoPlan(P3).(*xxx)
        convey.So(res.RetCode, convey.ShouldEqual, "000000")
    })
}

  

  

 

 

 

 

 

 

  

posted @   -零  阅读(471)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
历史上的今天:
2020-08-07 Python Http请求json解析库
2020-08-07 监听Rabbitmq系统日志(python版)
2020-08-07 Mysql主从复制
点击右上角即可分享
微信分享提示