【测试平台系列】第一章 手撸压力机(十一)-初步实现性能测试

简介: 上一章节我们组合了场景,它是一个list结构。今天我们实现性能测试计划的数据结构及其方法.

上一章节我们组合了场景,它是一个list结构。今天我们实现性能测试计划的数据结构及其方法。
首先,我们在model目录新建test_plan.go文件:

// Package model -----------------------------
// @file      : test_plan.go
// @author    : 被测试耽误的大厨
// @contact   : 13383088061@163.com
// @time      : 2023/8/14 12:06
// -------------------------------------------
package model

import (
        "kitchen-engine/global/constant"
        "time"
)

type TestPlan struct {
        Id         string      `json:"id"`      // 唯一id
        Name       string      `json:"name"`    // 场景名称
        ItemId     string      `json:"item_id"` // 项目Id
        TeamId     string      `json:"team_id"` // 团队Id
        Task       Task        `json:"task"`       // 具体的任务
        TestScenes []TestScene `json:"test_scenes"` // 执行的场景列表
}

我们需要给测试计划配上具体的测试任务。
上述代码中的Task为测试任务结构,在model下新建task.go:

// Package model -----------------------------
// @file      : task.go
// @author    : 被测试耽误的大厨
// @contact   : 13383088061@163.com
// @time      : 2023/8/14 13:48
// -------------------------------------------
package model

/* 
        测试任务,我们先实现根据时长并发数模式
**/


type Task struct {
        ConcurrentUsers int64  `json:"concurrent_users"` // 并发用户数
        TimeType        string `json:"time_type"`        // 时间的类型 时:h   分:m   秒:s
        Duration        int64  `json:"duration"`         // 持续时长
}

我们实现一个计划可以运行多个场景,所以使用[]TestScene列表的机构,这样我们一个计划就包含了多个场景。下面我们优化一下,上一章节中的TestScene结构体的Dispose()方法,优化后如下:

// 优化前
func (testScene TestScene) Dispose() {
        // 从testScene.TestObjects的最外层开始循环
        for _, testObject := range testScene.TestObjects {
                // 声明一个waitGroup控制等待内层循环请求内部完成
                wg := sync.WaitGroup{}
                // 从一层级的list中读取每个TestObject对象
                wg.Add(1)
                go func(object TestObject) {
                        defer wg.Done()
                        response := TestObjectResponse{
                                Name:       object.Name,
                                Id:         object.Id,
                                SceneId:    testScene.Id,
                                ItemId:     object.ItemId,
                                ObjectType: object.ObjectType,
                        }
                        // 开始进行请求处理
                        object.Dispose(&response)
                }(testObject)
                // 等待内层的list完成后,再开始下一次外层循环
                wg.Wait()
        }

}


// 优化后
func (testScene TestScene) Dispose() {
        // 从testScene.TestObjects的最外层开始循环
        for _, testObject := range testScene.TestObjects {
                response := &TestObjectResponse{
                        Name:       testObject.Name,
                        Id:         testObject.Id,
                        SceneId:    testScene.Id,
                        ItemId:     testObject.ItemId,
                        ObjectType: testObject.ObjectType,
                }
                testObject.Dispose(response)
                // 从一层级的list中读取每个TestObject对象
        }

}

下面,我们实现一下TestPlan的Dispose函数, test_plan.go:

// 处理测试计划
func (testPlan TestPlan) Dispose() {

        duration := time.Duration(testPlan.Task.Duration)

        // 将时分转换为秒, 默认为秒
        switch testPlan.Task.TimeType {
        case constant.H:
                duration = duration * 3600
        case constant.M:
                duration = duration * 60
        }

        users := testPlan.Task.ConcurrentUsers
        testScenes := testPlan.TestScenes

        // 使用协程同时处理计划中的所有场景
        for _, testScene := range testScenes {
                go disposePlan(users, duration, testScene)
        }

}



// 开始进行并发处理
func disposePlan(users int64, duration time.Duration, testScene TestScene) {

        // 启动所有的用户,每个协程代表一个用户
        for i := int64(0); i < users; i++ {
                // 每个协程都配备一个定时器,时间到后,自动停止任务
                timer := time.NewTimer(duration * time.Second)
                go func() {
                        // 使用for循环和select进行定时控制
                        for {
                                select {
                                case <-timer.C: // 当到达持续时间后,停止任务
                                        log.Logger.Debug("定时器结束。。。。。。。。。。。。。。。。。")
                                        timer.Stop() // 先把定时器停止掉,防止内泄露
                                        return       // 退出
                                default:
                                        testScene.Dispose()
                                }
                        }

                }()
        }
}

这样,我们就可以简单的实现的性能任务测试了,下面我们实现一下testPlan的api,方便我们通过接口进行调用。
在service目录下新建stress_test_plan.go

// Package service -----------------------------
// @file      : stress_test_plan.go
// @author    : 被测试耽误的大厨
// @contact   : 13383088061@163.com
// @time      : 2023/8/14 14:23
// -------------------------------------------
package service

import (
        "encoding/json"
        "fmt"
        "github.com/gin-gonic/gin"
        "github.com/google/uuid"
        "kitchen-engine/global/common"
        "kitchen-engine/global/log"
        "kitchen-engine/model"
        "net/http"
)

func StressRunTestPlan(c *gin.Context) {
        // 声明一个TO对象
        var testPlan model.TestPlan

        // 接收json格式的请求数据
        err := c.ShouldBindJSON(&testPlan)
        id := uuid.New().String()
        // 如果请求格式错误
        if err != nil {
                log.Logger.Error("请求数据格式错误", err.Error())
                common.ReturnResponse(c, http.StatusBadRequest, id, "请求数据格式错误!", err.Error())
                return
        }

        // 使用json包解析以下TO对象, 解析出来为[]byte类型
        requestJson, _ := json.Marshal(testPlan)
        // 打印以下日志, 使用fmt.Sprintf包格式花数据,%s 表示string(requestJson)为字符串类型,如果不确定类型,可以使用%v表示
        log.Logger.Debug(fmt.Sprintf("测试对象: %s", string(requestJson)))

        // 如果场景为空,直接返回
        if testPlan.Task.ConcurrentUsers <= 0 {
                common.ReturnResponse(c, http.StatusBadRequest, id, "请求错误!", "并发数不能小于等于0")
                return
        }
        if testPlan.Task.Duration <= 0 {
                common.ReturnResponse(c, http.StatusBadRequest, id, "请求错误!", "运行时间不能小于等于0")
                return
        }

        if len(testPlan.TestScenes) <= 0 || len(testPlan.TestScenes[0].TestObjects) <= 0 {
                common.ReturnResponse(c, http.StatusBadRequest, id, "请求错误!", "计划中的场景不能为空")
                return
        }

        // 开始处理TP
        testPlan.Dispose()
        // 返回响应消息
        common.ReturnResponse(c, http.StatusOK, id, "请求成功!", "success")
        return
}

router.go
// Package routers -----------------------------
// @file      : router.go
// @author    : 被测试耽误的大厨
// @contact   : 13383088061@163.com
// @time      : 2023/6/29 13:54
// -------------------------------------------
package routers

import (
        "github.com/gin-gonic/gin"
        "kitchen-engine/service"
)

/*
  路由配置
*/
func initRouters(groups *gin.RouterGroup) {
        {
                groups.POST("/run/testObject/", service.RunTestObject)          //运行测试对象接口, url: http://*****/engine/run/testObject/
                groups.POST("/run/testScene/", service.RunTestScene)            //运行场景接口, url: http://*****/engine/run/testObject/
                groups.POST("/run/stress/testPlan/", service.StressRunTestPlan) //运行性能测试计划接口, url: http://*****/engine/run/stress/testPlan/

        }

}

我们在根目录下新建expample-json目录,这里存放我们请求本服务的json文件。
运行对象调试的json: object.json

接口: http://127.0.0.1:8002/engine/run/testObject/

{
    "name": "百度",
    "id": "12312312312312",
    "object_type": "HTTP1.1",
    "item_id": "12312312312312",
    "team_id": "1231231231231",
    "http_request": {
        "url": "http://www.baidu.com",
        "method": "GET",
        "request_timeout": 5,
        "headers": [],
        "querys": [],
        "cookies": [],
        "http_client_settings": {}
    }
}

运行场景调试的json:scene.json

接口:http://127.0.0.1:8002/engine/run/testScene/


{
    "name": "调试百度",
    "id": "dlsjflksdjflks",
    "item_id": "12312312312312",
    "team_id": "1231231231231",
    "test_objects": [
        {
            "name": "百度",
            "id": "12312312312312",
            "object_type": "HTTP1.1",
            "item_id": "12312312312312",
            "team_id": "1231231231231",
            "http_request": {
                "url": "http://www.baidu.com",
                "method": "GET",
                "request_timeout": 5,
                "headers": [],
                "querys": [],
                "cookies": [],
                "http_client_settings": {}
            }

        }
    ]
}

运行性能测试计划json: plan.json

接口: http://127.0.0.1:8002/engine/run/stress/testPlan/


{
    "id": "lkjflksjlfjsjlflsfjfskldj",
    "name": "性能测试百度接口",
    "item_id": "12312312312312",
    "team_id": "1231231231231",
    "task": {
        "concurrent_users": 5,
        "time_type": "s",
        "duration": 5
    },
    "test_scenes": [
        {
            "name": "调试百度",
            "id": "dlsjflksdjflks",
            "item_id": "12312312312312",
            "team_id": "1231231231231",
            "test_objects": [
                {
                    "name": "百度",
                    "id": "12312312312312",
                    "object_type": "HTTP1.1",
                    "item_id": "12312312312312",
                    "team_id": "1231231231231",
                    "http_request": {
                        "url": "http://www.baidu.com",
                        "method": "GET",
                        "request_timeout": 5,
                        "headers": [],
                        "querys": [],
                        "cookies": [],
                        "http_client_settings": {}
                    }

                }
            ]
        }
    ]
}

大家,可以在自己电脑运行一下,使用访问一下这几个接口试试。

相关文章
|
3月前
|
关系型数据库 MySQL 测试技术
【分享】AgileTC测试用例管理平台使用分享
AgileTC 是一个脑图样式测试用例管理平台,支持用例设计、执行与团队协作,帮助测试人员高效管理测试流程。
290 116
【分享】AgileTC测试用例管理平台使用分享
|
3月前
|
人工智能 数据可视化 测试技术
AI测试平台自动遍历:低代码也能玩转全链路测试
AI测试平台的自动遍历功能,通过低代码配置实现Web和App的自动化测试。用户只需提供入口链接或安装包及简单配置,即可自动完成页面结构识别、操作验证,并生成可视化报告,大幅提升测试效率,特别适用于高频迭代项目。
|
3月前
|
人工智能 测试技术 调度
写用例写到怀疑人生?AI 智能测试平台帮你一键生成!
霍格沃兹测试开发学社推出AI智能测试用例生成功能,结合需求文档一键生成高质量测试用例,大幅提升效率,减少重复劳动。支持自定义提示词、多文档分析与批量管理,助力测试人员高效完成测试设计,释放更多时间投入核心分析工作。平台已开放内测,欢迎体验!
|
3月前
|
人工智能 测试技术 项目管理
测试不再碎片化:AI智能体平台「项目资料套件」功能上线!
在实际项目中,需求文档分散、整理费时、测试遗漏等问题常困扰测试工作。霍格沃兹推出AI智能体测试平台全新功能——项目资料套件,可将多个关联文档打包管理,并一键生成测试用例,提升测试完整性与效率。支持套件创建、文档关联、编辑删除及用例生成,适用于复杂项目、版本迭代等场景,助力实现智能化测试协作,让测试更高效、更专业。
|
4月前
|
存储 人工智能 算法
AI测试平台实战:深入解析自动化评分和多模型对比评测
在AI技术迅猛发展的今天,测试工程师面临着如何高效评估大模型性能的全新挑战。本文将深入探讨AI测试平台中自动化评分与多模型对比评测的关键技术与实践方法,为测试工程师提供可落地的解决方案。
|
6月前
|
存储 测试技术 虚拟化
VMmark 4.0.3 - 虚拟化平台基准测试
VMmark 4.0.3 - 虚拟化平台基准测试
196 0
VMmark 4.0.3 - 虚拟化平台基准测试
|
3月前
|
人工智能 自然语言处理 测试技术
AI测试平台的用例管理实践:写得清晰,管得高效,执行更智能
在测试过程中,用例分散、步骤模糊、回归测试效率低等问题常困扰团队。霍格沃兹测试开发学社推出的AI测试平台,打通“用例编写—集中管理—智能执行”全流程,提升测试效率与覆盖率。平台支持标准化用例编写、统一管理操作及智能执行,助力测试团队高效协作,释放更多精力优化测试策略。目前平台已开放内测,欢迎试用体验!
|
4月前
|
存储 人工智能 文字识别
从零开始打造AI测试平台:文档解析与知识库构建详解
AI时代构建高效测试平台面临新挑战。本文聚焦AI问答系统知识库建设,重点解析文档解析关键环节,为测试工程师提供实用技术指导和测试方法论
|
4月前
|
人工智能 安全 数据可视化
安全测试平台的选型标准与搭建思路
随着企业安全需求升级,传统漏洞扫描和渗透测试已无法满足要求。构建安全测试平台(STP)成为趋势,实现漏洞扫描、权限评估、接口测试等工作的平台化运营。本文从选型标准、平台架构、模块功能等六个方面,系统讲解如何搭建企业级安全测试平台,提升安全能力。
|
7月前
|
安全 前端开发 Linux
Immunity CANVAS Professional 7.27 (macOS, Linux, Windows) - 渗透测试和漏洞利用平台
Immunity CANVAS Professional 7.27 (macOS, Linux, Windows) - 渗透测试和漏洞利用平台
217 3
Immunity CANVAS Professional 7.27 (macOS, Linux, Windows) - 渗透测试和漏洞利用平台