天天看點

QTA-qtaf自動化測試實踐

QTA-qtaf自動化測試實踐

背景:

  • 項目leader認為萬物皆可自動化,然後就拍腦袋要搞個自動化,後面搞不下去了,涼了。雖然說項目涼了,但是過程中收獲滿滿,是以脫敏後就有了這篇部落格:javascript:void(0)

需求:

  • 需要把自動化做成一個服務,提供給背景調用
  • 對測試進度量化,如:測試進度的百分比
  • 測試報告定制化,如:展示一個測試用例資訊、測試标題、測試步驟等
  • 可以在前端選擇執行哪些用例,支援單個用例執行。

隐藏需求:

  • 我們要自己寫用例
  • 執行用例的不是我們

概要設計

  • 測試對象:http/https接口、web系統(後續方向)、app等(後續方向),基于此平台設計的自動化架構要包含測試用例管理、測試執行控制、測試報表及測試日志的生成,整體測試架構要輕量易用。
  • 整個服務分兩個部分,一是部分提供http接口對接外部服務,這裡就不詳述了,二是提供自動化部分。
  • 自動化部分總共分為5個公共庫子產品(可複用函數、日志管理)、用例倉庫(具體用例的管理)、頁面管理(單獨對Web頁面或接口進行抽象,封裝頁面元素和操作方法)、執行子產品(測試計劃和執行計劃)以及靜态資源,子產品之間不是互相孤立的,而是相輔相成的。

詳細設計

  • 用 qtaf 來管理用例,基礎詳情可以看 官方文檔
  • 然後基礎功能都有了。官方文檔比較詳細,這裡就不複制粘貼了。

拓展 testplan

點選檢視代碼

from testbase.loader import TestLoader
from testbase.plan import TestPlan
from testbase.runner import TestRunner


class XxxxTestPlan(TestPlan):
    tests = TestLoader().load("testcase.demo")
    test_target_args = ""

    hosts = ""

    def get_test_target(self):
        """擷取被測對象詳情"""
        return self.tests

    def test_setup(self, report):
        """全局初始化"""
        pass

    def resource_setup(self, report, restype, resource):
        """測試資源初始化"""
        pass


if __name__ == "__main__":

    from testbase.resource import LocalResourceManagerBackend
    from testbase.report import HtmlTestReport

    dir_report = {}
    TestRunner(
        HtmlTestReport(), resmgr_backend=LocalResourceManagerBackend()
    ).run(SstcTestPlan())
    print(dir_report)

           

拓展 測試報告

  • 把測試進度寫到redis裡
  • 把測試報告傳回回去
import argparse

from testbase.report import ITestResultFactory, report_usage, JSONTestReportBase
from testbase.testresult import JSONResult


class XxxxResult(JSONResult):
    """xxxx test result,先不處理後續有需要再寫"""

    def get_file(self):
        """
        重寫了父類方法,直接讓每個測試用例的結果弄到測試報告中
        ,而不是以一個檔案的形式單獨存在
        # TODO: 目前未遇到記憶體問題,後續考慮寫到redis裡
        @return:
        @rtype:
        """
        return self._data


class XxxxTestResultFactory(ITestResultFactory):
    """result factory"""

    def create(self, testcase):
        return XxxxResult(testcase)


class XxxxTestReport(JSONTestReportBase):
    """test report class"""

    def __init__(self, dict_report, task_id=None, count_tests=None, redis=None):
        super(JSONTestReportBase, self).__init__()
        self._logs = []
        self._filtered_tests = []
        self._load_errors = []
        self._passed_tests = {}
        self._failed_tests = {}
        self._data = dict_report
        self._data.update(
            {
                "version": "1.0",
                "summary": {"tool": "SSTC", "title": "", "environment": {}},
                "logs": self._logs,
                "filtered_tests": self._filtered_tests,
                "load_errors": self._load_errors,
                "passed_tests": self._passed_tests,
                "failed_tests": self._failed_tests,
            }
        )
        self._testcase_names = set()
        self._testcase_total_run = 0
        self._task_id = task_id
        self._count_tests = count_tests
        self._redis = redis

    def _set_task_progress(self, time_out=3600):
        """
        設定redis測試進度
        key: "tests_task_{}".format(self._task_id)
        value: 百分比   如:100、29
        @return:
        @rtype:
        """
        if self._task_id == None or self._count_tests == None or self._redis == None:
            return
        else:
            if self._count_tests == 0:
                self._redis.set("tests_task_{}".format(self._task_id), 0)
            else:
                self._redis.expire("tests_task_{}".format(self._task_id), time_out)
                self._redis.set(
                    "tests_task_{}".format(self._task_id),
                    int(
                        (len(self._passed_tests) + len(self._failed_tests))
                        * 100
                        / self._count_tests
                    ),
                )

    def log_test_result(self, testcase, testresult):
        self._set_task_progress()
        super(XxxxTestReport, self).log_test_result(testcase, testresult)

    def get_testresult_factory(self):
        """擷取對應的TestResult工廠
        :returns ITestResultFactory
        """
        return XxxxTestResultFactory()

    def end_report(self):
        super(XxxxTestReport, self).end_report()

    def begin_report(self):
        super(XxxxTestReport, self).begin_report()
        pass


           

使用感受和結論

  • 在qta這套架構在騰訊外用得基本上沒有文檔,然後官方提供的qq群也不活躍,所有要用的人考慮遇到問題後得自己能看得懂源碼(大多數注釋都是中文)
  • pyhon3支援得不是很好,所有用python3容易遇到版本相容問題(相關的依賴包)
  • 如果單純的隻用qtaf,不用其他配套架構qt4i,qt4w這類的會比較容易,不容易出現深坑。
  • 騰訊外沒有metis這個這套架構的核心可以用(2021年9月),有條件可以自己去實作。
  • 雖然架構提供了并發執行測試用例,但如果想執行效率更高需要自己定制開發執行器

結論:

  • 雖然說社群沒有其他架構(appium、selenium等)那麼活躍,但提供的基礎功能很全,且有全中文官方文檔對英語不好的人很友好,如果其他選擇你都不滿意,那麼qta全家桶你可以嘗試下。