YApi 服務端測試新增 globalCookie ,相容自動化觸發服務端測試功能

少年發表於2020-02-25

如果有用過 YApi,還試過測試功能,沒準會提過一個類似的 issues: 為什麼本地執行介面測試正常,但是服務端測試卻不正常呢?

這個主要是因為本地是用瀏覽器來跑的,同在一個集合的介面用例,前面 set-cookie 以後,後面的 cookie 會直接從瀏覽器裡面讀,也就保持了前後一致性。但是,你用服務端來跑的時候,就算是同一個集合的測試用例,它的 cookie 值並沒有完全保持前後一致,這也就導致了為什麼本地跑可以,但是服務端測試不行。

但是很多時候我們做 ci 工具的時候,也就是我們想把介面測試做成,提交程式碼以後自動觸發執行並失敗告警的自動化流程裡面去的時候,往往需要的都是它的服務端測試的功能,所以服務端測試的 cookie 前後一致性的功能,也就很有必要了。

然鵝,這個 globalCookie 並沒有隨著 YApi 的更新也一起加上,所以,又到了自己動手豐衣足食的環節。

原專案太大了沒必要全部拉下來,這裡我直接 fork 了一個 yapi 的 docker 部署,然後我們只需要修改一些程式碼,新增到 Dockfile 裡面去,打出來的映象也就具備了 globalCookie 的功能。

專案程式碼:yapi-globalCookie【又到了歡迎來 star 的時刻!】

COPY open.js /yapi/vendors/server/controllers/

Dockerfile 裡面加了這句話,看了一下 YApi 的程式碼,涉及到介面測試的執行方式主要跟這個 /yapi/vendors/server/controllers/open.js 的檔案有關係,我們可以在執行服務端測試的時候,將 cookie 設定成全域性變數,每當出現 set-cookie 的時候就儲存下來,用於後面的請求,也就具備了 globalCookie 的功能。

var _globalCookies = false;

async webHandleTest(interfaceData) {
    let requestParams = {};
    let options;
    options = handleParams(interfaceData, this.handleValue, requestParams);

    if (_globalCookies) {
      options.headers['Cookie'] = _globalCookies;
    }

    let result = {
      id: interfaceData.id,
      name: interfaceData.casename,
      path: interfaceData.path,
      code: 400,
      validRes: []
    };

    try {
      options.taskId = this.getUid();
      let data = await crossRequest(options, interfaceData.pre_script, interfaceData.after_script,createContex(
        this.getUid(),
        interfaceData.project_id,
        interfaceData.interface_id
      ));
      let res = data.res;

      if (res.header['set-cookie']) {
        let arrCookie = res.header['set-cookie'].toString().split(',');
        var tmp = '';
        for (let i = 0;i < arrCookie.length; i++) {
          let idx = arrCookie[i].indexOf(';');
          if (tmp.length > 0) {
            tmp += '; ';
          }
          tmp += arrCookie[i].substring(0, idx);
        }
        _globalCookies = tmp;
      }

      result = Object.assign(result, {
        status: res.status,
        statusText: res.statusText,
        url: data.req.url,
        method: data.req.method,
        data: data.req.data,
        headers: data.req.headers,
        res_header: res.header,
        res_body: res.body
      });
      if (options.data && typeof options.data === 'object') {
        requestParams = Object.assign(requestParams, options.data);
      }

      let validRes = [];

      let responseData = Object.assign(
        {},
        {
          status: res.status,
          body: res.body,
          header: res.header,
          statusText: res.statusText
        }
      );

      await this.handleScriptTest(interfaceData, responseData, validRes, requestParams);
      result.params = requestParams;
      if (validRes.length === 0) {
        result.code = 0;
        result.validRes = [{ message: '驗證透過' }];
      } else if (validRes.length > 0) {
        result.code = 1;
        result.validRes = validRes;
      }
    } catch (data) {
      result = Object.assign(options, result, {
        res_header: data.header,
        res_body: data.body || data.message,
        status: null,
        statusText: data.message,
        code: 400
      });
    }

    return result;
  }

PS:技術交流 QQ 群 552643038

相關文章