• 第一,自动化代码能够做到 修改一两处就能维护好这些受影响的用例,我感觉其实更花精力,还必须得项目很稳定。
    第二, 修改一两处就能维护好这些受影响的用例,这种情况太理想了,更多时候 UI 是全部大改的,代码基本要重写。而且你要应用的项目不止一个,有 N 个项目都在迭代更新,真的能有这么多份写好的自动化代码吗?
    第三,本身手工测试,就是要点点点,只不过这次,在 dev 环境点完了,开了录制,接下来就可以在 test / staging / release 上快速回归,不需要投入会写代码的人力物力。
    第四,如果真的能够定位到 修改一两处就能维护好这些受影响的用例,其实对于录制来说,真的不用重新录,把某些改动的地方匹配替换一下就行了。

  • 不用维护,哪些 UI 改了就重录替代用例,快录快用。目的是没改的快速回归,以及很多第三方的置入功能,比如 mock 比如 埋点监听 等等。

  • 愿闻其详

  • 目前只做了基于 puppeteer 的,mitmproxy / anyproxy 都可以扩展兼容。

  • 持续思考,持续进步 hhh

  • 正解

  • Locust 从入门到实战 at 2020年12月01日

    真要看重性能,可能你得看下 boomer

  • ......

  • 时间戳,上下游响应之类的关联信息,你要想伪造那份 log 不好搞,不如直接自己写个 log 生成 request 的发生器

  • 因为我用的是 mac 当然这样写。Chromium 又不是只有 mac 版本,换一下就行。

  • 字节游戏测试 (外包岗位) at 2020年11月06日

    不要去外包!
    不要去外包!
    不要去外包!

  • 可以的,你在执行的时候保存下 log,然后写个页面每次去获取这个 log,解析一下包装成你想要的数据就行了。

  • 才看到 hhh
    是鸭,趋势所在

  • 那就是 grafana 里面设置连接数据库的信息不对。

    你选 server 模式的时候,不能写 http://localhost:9090 http://127.0.01:9090,要填本机的真实 ip 地址。

  • 七牛云 goc docker 部署 at 2020年10月29日

    传错地方了,已上传,再试一下~

  • 七牛云 goc docker 部署 at 2020年10月28日

    要带 tag,docker pull shaonian/goc:v1.0

    你直接用 docker-compose 起不就完了,干嘛一个个单独拉。

  • 你不是用 docker-compose.yml 起的吗

  • 你应该还没有执行压测吧,没有执行压测那肯定没有测试数据。

    如果不是这个问题,就得看看容器的日志,你截图页面没啥意义。

    还有要注意一下 grafana 里面配置 prometheus 的一些连接信息,这里不对也会这样。

  • 你这个是 window 10 家庭版,不是专业版,没有打开 Hyper-V 的选项。

    要打开这个才能装 docker。

  • hhhhh

  • 为什么要做自动化? at 2020年10月16日
    1. 直接代码层面引入第三方插件,智能生成 api 文档。(比如其他人说的 swagger)

    2. 脚本实现,抓数据,手写转 swagger 格式。

    3. 借助第三方平台实现,现在 yapi 接口管理平台可以导入 har 当文档了,对你来说,应该是最佳选择鸭。


  • 你要明白一个问题,那就是为啥这里只有 max-rps 没有什么 min-rps 。。。

    你说的 在 locust 中可以通过 Semaphore 来等待 2000 个 VU 起来

    boomer 不用等,开多几个 pod 开场就 2000 个 goroutine。。。

    对于 go 来说,只要资源充足,你一开始就能直接产生 2000 个 goroutine,甚至能更多 。。。

    --max-rps 是怕并发太多你系统撑不过来,用来限制协程并发数的。。。

    你看看实现。

    // Start to refill the bucket periodically.
    func (limiter *RampUpRateLimiter) Start() {
        limiter.quitChannel = make(chan bool)
        quitChannel := limiter.quitChannel
        // bucket updater
        go func() {
            for {
                select {
                case <-quitChannel:
                    return
                default:
                    atomic.StoreInt64(&limiter.currentThreshold, limiter.nextThreshold)
                    time.Sleep(limiter.refillPeriod)
                    close(limiter.broadcastChannel)
                    limiter.broadcastChannel = make(chan bool)
                }
            }
        }()
        // threshold updater
        go func() {
            for {
                select {
                case <-quitChannel:
                    return
                default:
                    nextValue := limiter.nextThreshold + limiter.rampUpStep
                    if nextValue < 0 {
                        // int64 overflow
                        nextValue = int64(math.MaxInt64)
                    }
                    if nextValue > limiter.maxThreshold {
                        nextValue = limiter.maxThreshold
                    }
                    atomic.StoreInt64(&limiter.nextThreshold, nextValue)
                    time.Sleep(limiter.rampUpPeroid)
                }
            }
        }()
    }
    

    你只要不设置 rampUpPeroid rampUpStep 只设置 maxThreshold

    资源充足的情况下马上就能触发这个逻辑。

    if nextValue > limiter.maxThreshold {
        nextValue = limiter.maxThreshold
    }
    

    至于你说的 并发每隔一分钟来一次

    boomer 并发的是函数,你在函数结尾直接 sleep 一分钟,不就 2000 并发一次了吗。。。

  • 具体例子已给出 ~ 见最佳回复

  • 按日志格式造 request 实现不难,难的是把业务逻辑和规则融入进去,就比如你的第二个问题,才是第一个问题的核心。

    举个例子:

    线上日志

    GET /product
    HOST prod.com
    PARAM token: old-token
    PARAM name: 1-prod-product
    

    发起 prod 请求前,复制一份到 test,更改 HOST 和 匹配规则

    if host == "test.com" && "url == /product" 匹配 替换类规则 RULE [1,2]

    RULE 1 代表登录类替换逻辑,若 PARAM 匹配到 token cookie ..., 替换成万能 token 或调用函数造 token。
    RULE 2 代表关联类替换逻辑,若 PARAM 匹配到 name ... ,根据 get_product(host,token) 获取对应环境的值并替换。

    GET /product
    HOST test.com
    PARAM token: new-token
    PARAM name: 2-test-product
    

    然后同时发出,然后 diffy json(response_prod, response_test)

    这里还可以做噪音匹配规则,这样对照组都能省,直接去噪。
    比如增加 NOISE_RULE [1]
    NOISE_RULE 1 代表通用类去噪音规则,diffy --ignore time, createtime, updatetime...

    最后,再借助 boomer 登记 diffy,就可以自己直接实现 diffy 归纳路由。

    if diff := jsondiff.Diff(response_prod, response_test, diffopts.IgnorePaths([]string{"/time"})); diff != "": {
        boomer.RecordFailure("GET", "/product", 0, string(diff))
    }
    

    PS:

    正确打开方式之前的两幅图,一个是 buger/goreplay 的回放,以及 opendiffy/diffy 的差异对比,这也是传统模式的 录制 + 回放,主要讲解传统模式 录制 + 回放 的原理,以及落地以后的一些缺陷。

    而后提出的优化,也是基于体验这个流程以后,弥补其中的一些不足,并提出优化实现方案。

  • 可以理解为,把线上的流量录制成特定的日志格式,脚本是解析日志格式去发请求的,只要格式保持一致,就通用于大部分的项目。然后,涉及标记的动态数据得替换生成。

    不过能理解成接口自动化 + 压测也对,原理都是把请求经过处理,同时对多个服务发出,并实时 diffy 响应。只不过一个是手写代码构造 request 一个是读线上日志构造 request。