Administrator
发布于 2022-04-14 / 6464 阅读
88

接口自动化测试与 CI 集成

一次发布把下单接口打挂了,CI 里却全是绿的

4 月一次常规发布后,下单接口 5xx 飙到 12%。回看 CI 流水线,单元测试全绿。问题出在:单元测试只覆盖了方法内部逻辑,没人验证"接口契约"本身——前端传的字段名改了,后端字段名也跟着改,但两边没对齐,网关层反序列化直接失败。

这事之后我把接口自动化测试和 CI 质量卡点补齐了。这里记的是落地方式,不是工具清单。

契约测试:在 CI 里锁住接口约定

我们前后端用 OpenAPI(Swagger)定义契约。之前契约是文档,写完就过时。现在用 契约测试把文档变成可执行断言。

用 Spring Cloud Contract 的话,契约文件由后端定义、前端消费:

# src/contracts/order/create.groovy
Contract.make {
    request {
        method 'POST'
        url '/api/order'
        body([ userId: 1001, skuId: 88, qty: 2 ])
        headers { contentType(applicationJson()) }
    }
    response {
        status 200
        body([ orderId: $(anyNumber()), payUrl: $(anyUrl()) ])
        headers { contentType(applicationJson()) }
    }
}

CI 里跑这个契约,会自动生成对后端实现的测试,校验真实接口返回是否满足约定。前端那边用同一份契约生成 stub,联调时不用等后端起服务。那次字段名不一致的事故,就是契约测试在合并前拦下来的——它发现响应里少了一个 payUrl 字段。

用例管理:别让测试变成一次性代码

很多团队的接口测试写一次就荒废,因为用例散在脚本里、没人维护。我们定了几条规矩:

  • 用例跟着接口版本走,放在仓库 src/test/contract,和代码一起评审、一起回滚。
  • 覆盖三层:正常路径、边界值(qty=0、qty 超库存)、异常路径(用户不存在返回 4xx)。
  • 用统一 base URL 从环境变量读,本地、测试环境、CI 各一套,不把地址写死
@SpringBootTest(webEnvironment = RANDOM_PORT)
class OrderApiTest {
    @Value("${api.base-url}") String base;

    @Test
    void createOrder_ok() {
        given().baseUri(base).header("Content-Type","application/json")
          .body("{\"userId\":1001,\"skuId\":88,\"qty\":2}")
          .when().post("/api/order")
          .then().statusCode(200)
          .body("orderId", notNullValue());
    }
}

我们用 REST Assured 写这种用例,读起来接近自然语言,新同事也能维护。

流水线质量卡点:不是能跑就行,是卡得住

把测试接进 GitLab CI,关键是卡点设计

stages:
  - test
  - contract
  - build
  - deploy

contract_test:
  stage: contract
  script:
    - mvn verify -Pcontract
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request"'
  allow_failure: false        # 失败就阻断合并

我设了三道卡点,按成本从低到高排:

卡点触发时机失败后果耗时
单元测试每次 push阻断本次构建~40 s
契约测试合并请求阻断合并~90 s
接口自动化(对测试环境)部署后自动回滚~3 min

最后一道卡点在部署后跑,对刚发到测试环境的实例发真实请求,发现异常就触发 kubectl rollout undo 回滚。我们统计过,接入后"发布导致的线上故障"从每月 4 起降到 1 起。

踩的坑

  • 测试环境数据污染。接口测试会真写库,跑完一堆脏数据。后来给测试库加了个 事务回滚:每个用例用 @Transactional 包起来,跑完自动滚,环境永远干净。
  • 契约只测了后端,前端 stub 没同步更新,联调还是对不上。现在要求契约文件改动必须同时通知两端,CI 里前后端各跑一遍。

下篇预告

这篇先把《接口自动化测试与 CI 集成》里的坑列了,下一篇写我们当时是怎么在线上工程里真正落地的——包括那次让领导拍桌的故障复盘。

参考