专栏文章 实战 Hrp:手把手教你增加接口协议 -- 配置管理

扬帆自动化测试平台 · 2023年08月14日 · 2759 次阅读

源码

官网

demo 账号:admin,密码:123456

我们可以在 Go 语言中如何设置config。从response_test.go文件中的assertRunTestCases函数中,我们可以看到一种设置方法:

  1. 首先,我们通过NewConfig函数创建一个config对象。
  2. 使用SetWeight方法来设置负载测试中的权重,这将影响测试用例的执行频率。
  3. 通过SetTimeout方法设置请求的超时时间,确保在指定时间内完成请求。
  4. 使用SetHeaders方法来设置请求头,这可以为请求添加所需的头部信息。

通过这些步骤,我们可以对config进行设置,以适应不同的测试需求。这种设计模式使得配置测试用例变得非常直观和灵活,可以根据具体的场景来调整参数,从而实现更加精确的测试。深入理解这些设置方法,将帮助我们在编写测试用例时更加得心应手。

func assertRunTestCases(t *testing.T) {
    testcase2 := &TestCase{
        Config: NewConfig("TestCase2").SetWeight(3),
    }
    testcase3 := &TestCase{
        Config: NewConfig("TestCase3").SetWeight(3).SetTimeout(10).SetHeaders(map[string]string{"project":"扬帆"}),
    }
}

上述的写法属于链式调用,这种写法允许在同一个对象上连续调用多个方法,每个方法的返回值是对象本身的地址引用,从而可以在后续调用中继续使用其他方法。这样的设计使得代码更加简洁和易读。除了config,在测试步骤的Step中也广泛使用了链式调用。

为了更好地理解链式调用,我们可以通过一个简单的例子来说明。假设我们有一个名为IntList的结构体,它具有AddDoublePrint等方法,同时每个方法都返回 IntList 对象的地址引用。

当我们调用IntList.Add(1).Add(2).Add(3).Double().Print()时,实际上是在同一个IntList对象上连续调用了三个方法。每个方法的返回值都是该对象的地址引用,所以我们可以在每个方法调用后继续调用下一个方法。

这种设计方式在代码编写和阅读时都非常方便,能够使代码更加紧凑、易读,也减少了临时变量的使用。理解链式调用的核心是每个方法都返回对象本身的地址引用,使得后续方法可以继续在同一个对象上调用。

package main

import (
    "fmt"
)

// IntList 表示一个整数切片。
type IntList struct {
    data []int
}

// Add 向 IntList 中添加一个新元素。
func (l *IntList) Add(num int) *IntList {
    l.data = append(l.data, num)
    return l
}

// Double 将 IntList 中所有元素乘以 2。
func (l *IntList) Double() *IntList {
    for i := range l.data {
        l.data[i] *= 2
    }
    return l
}

// Print 打印 IntList 中的元素。
func (l *IntList) Print() *IntList {
    fmt.Println(l.data)
    return l
}

func main() {
    // 创建 IntList 并进行链式调用。
    IntList := &IntList{}
    IntList.Add(1).Add(2).Add(3).Double().Print()
}

在上述例子中,我们实现了链式调用,其中关键之处在于每个方法的返回值都是当前对象的指针。在配置中,以及用例的编写中,我们同样使用了链式调用的方式。这种方式在直接编写用例时非常方便,能够让代码更易于理解和编写。

如果我们在平台化的环境中操作,可以根据具体情况决定是否采用链式调用。在用例内部,数据可以被转换成用例格式,因此链式调用并非必须。然而,如果我们进行二次开发,也可以根据具体方案来灵活实现链式调用的需求。

在理解了链式调用方法后,我们可以进一步审视配置的内容。基本上,公共配置是相同的,而不同类型的用例(如httpwebsocketui等)的特定配置存放在配置中。在未来,我们还可以考虑将MQTT协议的发布者和订阅者实例放置在这个位置。这种统一的配置方式有助于管理和维护各种不同类型的用例,使得整个框架更加灵活和可扩展。

  • Name string: 测试用例的名称,必需字段。
  • Verify bool: https证书验证参数,可选字段。
  • BaseURL string: 基础 URL,在v4.1版本已废弃,已被移动到Environs字段中,可选字段。
  • Headers map[string]string: 公共请求头信息,键值对形式的字符串映射,可选字段。
  • Environs map[string]string: 环境变量,键值对形式的字符串映射,可选字段。
  • Variables map[string]interface{}: 全局变量,键值对形式的任意类型映射,可选字段。
  • Parameters map[string]interface{}: 参数,键值对形式的任意类型映射,可选字段。
  • ParametersSetting *TParamsConfig: 参数设置,一个指向TParamsConfig类型的指针,可选字段。
  • ThinkTimeSetting *ThinkTimeConfig: 思考时间设置,一个指向ThinkTimeConfig类型的指针,可选字段。
  • WebSocketSetting *WebSocketConfig: WebSocket设置,一个指向WebSocketConfig类型的指针,可选字段。
  • IOS []*uixt.IOSDevice: iOS设备配置,一个uixt.IOSDevice类型的切片,可选字段。
  • Android []*uixt.AndroidDevice: Android设备配置,一个uixt.AndroidDevice类型的切片,可选字段。
  • Timeout float64: 全局超时时间(单位:秒),可选字段。
  • Export []string: 导出配置,一个字符串切片,可选字段。
  • Weight int: 权重,一个整数,可选字段。
  • Path string: 测试用例文件路径,可选字段。
  • PluginSetting *PluginConfig: 插件配置,一个指向PluginConfig类型的指针,可选字段。
// TConfig represents config data structure for testcase.
// Each testcase should contain one config part.
type TConfig struct {
    Name              string                 `json:"name" yaml:"name"` // required
    Verify            bool                   `json:"verify,omitempty" yaml:"verify,omitempty"`
    BaseURL           string                 `json:"base_url,omitempty" yaml:"base_url,omitempty"`   // deprecated in v4.1, moved to env
    Headers           map[string]string      `json:"headers,omitempty" yaml:"headers,omitempty"`     // public request headers
    Environs          map[string]string      `json:"environs,omitempty" yaml:"environs,omitempty"`   // environment variables
    Variables         map[string]interface{} `json:"variables,omitempty" yaml:"variables,omitempty"` // global variables
    Parameters        map[string]interface{} `json:"parameters,omitempty" yaml:"parameters,omitempty"`
    ParametersSetting *TParamsConfig         `json:"parameters_setting,omitempty" yaml:"parameters_setting,omitempty"`
    ThinkTimeSetting  *ThinkTimeConfig       `json:"think_time,omitempty" yaml:"think_time,omitempty"`
    WebSocketSetting  *WebSocketConfig       `json:"websocket,omitempty" yaml:"websocket,omitempty"`
    IOS               []*uixt.IOSDevice      `json:"ios,omitempty" yaml:"ios,omitempty"`
    Android           []*uixt.AndroidDevice  `json:"android,omitempty" yaml:"android,omitempty"`
    Timeout           float64                `json:"timeout,omitempty" yaml:"timeout,omitempty"` // global timeout in seconds
    Export            []string               `json:"export,omitempty" yaml:"export,omitempty"`
    Weight            int                    `json:"weight,omitempty" yaml:"weight,omitempty"`
    Path              string                 `json:"path,omitempty" yaml:"path,omitempty"`     // testcase file path
    PluginSetting     *PluginConfig          `json:"plugin,omitempty" yaml:"plugin,omitempty"` // plugin config
}

配置的实现相对简单,我们可以定义一个结构体,并将需要在后续调用中使用的内容存储在配置中。通过使用链式调用的方法,我们可以为配置中的每个字段进行赋值。

在这种设计下,如果未来我们要增加MQTT协议的支持,只需要在配置中增加与MQTT相关的数据即可。

这种统一的配置方式使得我们可以更加灵活地管理不同类型的用例,而且通过链式调用的方式为配置赋值,使得代码更加清晰、易读,也方便后续的拓展和修改。这种设计模式在使得整个框架更加模块化和可扩展的同时,也为后续的功能添加提供了更加便捷的方式。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册