python单链路性能测试实践

引言

在经历过一些尝试之后,觉得在当下的项目中运用链路压测的能力,不等着其他人了。

链路这个词其实不如路径通俗易懂,跟产品沟通这个比较有效率。具体的操作路径,产品会给一份出来,但是这都是基于UI和产品思维的文档,跟接口测试区别还是很大的,只能提供参考依据。

需要端上测试协作,有些业务细节还得端上测试同学帮忙补充一下。还需要运维同事帮忙理一下各个接口的请求量比例,这次的比例我是依据灵光一现写出来,然后大家一起调整的。

本次由于比较初级,所以这块文档就不写出来了,放一个图来表达一下这个链路做了些什么,PS:我现在很喜欢用图而不是文字,沟通效率太高了。推荐工具draw.io,感兴趣的可以参考文末的热文中两张架构图中的介绍。

资源库1.4链路压测方案

这次把登录剔除了,因为太慢了,对测试结果影响比较大。

场景思路

场景

场景就是老师登录,首先会请求一个知识点列表,然后通过知识点属性筛选推荐课程列表,在对课程列表中的数据进行收藏和取消收藏,在获取自己当前知识点下的课程列表(包含原创和收藏)。

思路

本次依然采取固定线程的压测模型,本人预估线程200左右,测试用户600备用,列表页保证2页数据。

每个线程绑定一个用户,然后用户开始循环链路执行步骤,执行一次当做一次Q。单次Q包含9HTTP接口请求(放弃了Socket接口,以后有需求再添加Socket接口到链路中),其中3次修改操作,6次查询操作。

具体的逻辑通过内部静态类实现,然后多一个K类,用来存储每次获取的知识点属性,方便调用。由于接口请求方法都是用基础数据类型和String作为参数,所以调用时候会显得有点啰嗦。但无伤大雅,脚本写出来,本来就是用完就扔到仓库里面,改天再用再优化。

Demo实现

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

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

package com.okayqa.composer.performance.resource1_4

import com.alibaba.fastjson.JSON

import com.alibaba.fastjson.JSONObject

import com.funtester.base.bean.AbstractBean

import com.funtester.base.constaint.ThreadLimitTimesCount

import com.funtester.frame.execute.Concurrent

import com.funtester.httpclient.ClientManage

import com.funtester.utils.ArgsUtil

import com.okayqa.composer.base.OkayBase

import com.okayqa.composer.function.Mirro

import com.okayqa.composer.function.OKClass

class Login_collect_uncollect extends OkayBase {

    public static void main(String[] args) {

        ClientManage.init(1050, "", 0)

        def util = new ArgsUtil(args)

        def thread = util.getIntOrdefault(030)

        def times = util.getIntOrdefault(140)

        def tasks = []

        thread.times {

            tasks << new FunTester(it, times)

        }

        new Concurrent(tasks, "资源库1.4登录>查询>收藏>取消收藏链路压测").start()

        allOver()

    }

    private static class FunTester extends ThreadLimitTimesCount<Integer> {

        OkayBase base

        def mirro

        def clazz

        FunTester(Integer integer, int times) {

            super(integer, times, null)

        }

        @Override

        void before() {

            super.before()

            base = getBase(t)

            mirro = new Mirro(base)

            clazz = new OKClass(base)

        }

        @Override

        protected void doing() throws Exception {

         

            def klist = mirro.getKList()</code><code>            mirro.getKList()

            def karray = klist.getJSONArray("data")

            K ks

            karray.each {

                JSONObject parse = JSON.parse(JSON.toJSONString(it))

                if (ks == null) {

                    def level = parse.getIntValue("node_level")

                    def type = parse.getIntValue("ktype")

                    def id = parse.getIntValue("id")

                    ks = new K(idtype, level)

                }

            }

            JSONObject response = clazz.recommend(ks.id, ks.type, ks.level)</code><code>            clazz.recommend(ks.id, ks.type, ks.level)            clazz.recommend(ks.id, ks.type, ks.level)

            def minis = []

            int = 0

            response.getJSONArray("data").each {

                if (i++ &lt; 2) {

                    JSONObject parse = JSON.parse(JSON.toJSONString(it))

                    int value = parse.getIntValue("minicourse_id")

                    minis &lt;&lt; value

                }

            }

            clazz.unCollect(random(minis))

            mirro.getMiniCourseListV3(ks.id, ks.type0, ks.level)            mirro.getMiniCourseListV3(ks.id, ks.type0, ks.level)

        }

    }

    private static class K extends AbstractBean {

        int id

        int type

        int level

        K(int idint typeint level) {

            this.id = id

            this.type = type

            this.level = level

        }

    }

}

其中AbstractBean类是一个抽象类,用于一些bean的方法封装,就是为了省事儿。

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

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

package com.funtester.base.bean

import com.alibaba.fastjson.JSON

import com.alibaba.fastjson.JSONObject

import com.funtester.frame.Save

import com.funtester.frame.SourceCode

import org.slf4j.Logger

import org.slf4j.LoggerFactory

import org.springframework.beans.BeanUtils

/**

 * bean的基类

 */

abstract class AbstractBean {

    static final Logger logger = LoggerFactory.getLogger(AbstractBean.class)

    /**

     * 将bean转化为json,为了进行数据处理和打印

     *

     * @return

     */

    JSONObject toJson() {

        JSONObject.parseObject(JSONObject.toJSONString(this))

    }

    /**

     * 文本形式保存

     */

    def save() {

        Save.saveJson(this.toJson(), this.getClass().toString() + SourceCode.getMark());

    }

    /**

     * 控制台打印,使用WARN记录,以便查看

     */

    def print() {

        logger.warn(this.getClass().toString() + ":" + this.toString());

    }

    def initFrom(String str) {

        JSONObject.parseObject(str, this.getClass())

    }

    def initFrom(Object str) {

        initFrom(JSON.toJSONString(str))

    }

    def copyFrom(AbstractBean source) {

        BeanUtils.copyProperties(source, this)

    }

    def copyTo(AbstractBean target) {

        BeanUtils.copyProperties(this, target)

    }

    /**

     * 这里bean的属性必需是可以访问的,不然会返回空json串

     * @return

     */

    @Override

    String toString() {

        JSONObject.toJSONString(this)

    }

    @Override

    protected Object clone() {

        initFrom(this)

    }

}

控制台输出

~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~
>  {
>  ① . "rt":1665,
>  ① . "total":1188,
>  ① . "qps":18.018,
>  ① . "failRate":0.0,
>  ① . "threads":30,
>  ① . "startTime":"2021-02-24 16:57:23",
>  ① . "endTime":"2021-02-24 16:58:34",
>  ① . "errorRate":1.01,
>  ① . "executeTotal":1188,
>  ① . "mark":"资源库1.4登录>查询>收藏>取消收藏链路压测241657",
>  ① . "table":"eJzj5VLAD15sbXm2a8LTXZMN9Uyez9z9dO9Uu2fzl75Yv8ju2ZRtL6b32z3tn/ZsWweE83Lyvhfb1z/t6362tZvT2EChJKMoNaWYgA0KvFy8+F0RlFpckJ9XnKoQkpmbaqVQoVucWpSZmKOQV5qro1Cpm5uakpmYR8gOQq5QyM3MU4AYZWVhYqmQW6yTm1hhZWxoaQxkE9RNjA2UgEfTOoBo1JZRW2hmRSsQ0ccmsBW0tgnVQzS1DatVtLMRn3W0sPXRtCYgAlLtQITXWura/mhaMxCRYC+VXUGyv2nhmkfTGoGI0rCgrsseTWsBImLSIZ1dCA8sOjmMXNfCU9ZAupNYV8MdC4106qdA2vkAniAGq6OJ8AlVi6GB99FgSvTU8BU8egaBg6jsO3iWHwSuoZUPB4EzRn046sNRHw68M0Z9OOrDEe5DABkr1eo="
>  }
~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~

​现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
qq群号:485187702【暗号:csdn11】
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!

最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走! 希望能帮助到你!【100%无套路免费领取】

  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值