airTest 應用到項目並優化


之前已經介紹了airTest的原理,該文主要指引大家能夠將airTest框架應用到具體的測試項目當中去。

 

首先要考慮的是:

1. 你是用airTest 去做什么自動化 (android, ios, web)

2. airTest 能做什么,不能做什么,然后我們需要做出什么優化?

 

通過實際的使用,我其實發現airTest最大的優點是在元素識別方面,能夠讓沒有編碼基礎或者是編碼能力比較弱的人也可以編寫自動化測試腳本。

但是大家使用的時候也會發現airTest沒有良好的用例設計、管理機制。 沒有很好的參數管理,同時一個air文件會生成一個測試報告,沒有報告聚合的功能。

特別適用於:  通過外包執行功能測試的情況。 外包只要幫你錄入腳本就行了。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

我們需要優化的幾個地方:

1. 提供報告聚合功能,一次可以看多個用例的執行情況

2. Log聚合功能

3. 良好的用例設計/參數管理/方法封裝的功能。

4. 批量執行腳本的功能

 

批量執行腳本的代碼: (loggin.conf文件可以自行配置,這里不展開。)

 

import time

from airtest.cli.runner import AirtestCase, run_script
from argparse import *
import shutil
import os
import logging.config

logging.config.fileConfig('../logging.conf')
logger = logging.getLogger('root')
# alltestnames = allcase_list_new.case_list()
# alltestnames = ['webDemo.air', 'webDemo2.air']
# logger.info(alltestnames)
conf_root_dir = 'C:\\Python項目\\AirtestIDE_2019-01-15_py3_win64\\demo\\AirtestCase-master\\'


def init_log_folder():
    """初始化日志根目錄"""
    name = time.strftime("log_%Y%m%d_%H%M%S", time.localtime())
    if not os.path.exists(name):
        os.mkdir(name)
        print("creat file_dir: ", name)
    return namedef del_file(file_path):
    for name in os.listdir(file_path):
        if name.startswith("log_20"):
            try:
                shutil.rmtree(name)
            except Exception as e:
                print('filepath: ', file_path)
                print("del failed !!", e)


def copy_file(olddir_path, newdir_path):
    # 遍歷路徑內的文件,只是一層
    for name in os.listdir(olddir_path):
        if name.endswith(".txt"):  # 只復制特定類型文件
            # print (os.path.join(root, name))
            source = os.path.join(olddir_path, name)
            target = os.path.join(newdir_path, name)
            try:
                shutil.copy(source, target)
                # name.close()
            except:
                print("Copy %s failed!" % name)



class CustomAirtestCase(AirtestCase):
    def setUp(self):
        logger.info("custom setup")
        super(CustomAirtestCase, self).setUp()

    def tearDown(self):
        logger.info("custom tearDown")
        super(CustomAirtestCase, self).setUp()

    def run_air(self, root_dir, device):
        for f in os.listdir(root_dir):
            if f.endswith(".air"):
                # f為.air案例名稱:銀行.air
                script = os.path.join(root_dir, f)
                logger.info('執行腳本 :' + script)
                # 日志存放路徑和名稱
                # log = os.path.join(root_dir, + airName)
                # logger.info('用例log保存文件夾=' + log)
                logdir = os.path.join(conf_root_dir, init_log_folder())
                if os.path.isdir(logdir):
                    shutil.rmtree(logdir)
                else:
                    logger.info('日志路徑: ' + logdir)
                
                # output_file = log + '\\' + 'log.html'
                args = Namespace(device=device, log=logdir, recording=None, script=script)
                try:
                    run_script(args, AirtestCase)
                    # 將log和截圖文件等復制到腳本文件下,方便生成報告
                    copy_file(logdir, script)
                except Exception as e:
                    logger.exception(str(e))
                    pass


if __name__ == '__main__':
    test = CustomAirtestCase()
    # device = ['android:2d87aa41']
    # device = ['android:127.0.0.1:62001']
    device = ["windows:///"]
    # for d in device:
    test.run_air(conf_root_dir + '用例集', device)

 

 

 

 

聚合報告的代碼:

# -*- coding: utf-8 -*-

import os
import io
import types
import shutil
import json
import jinja2
from airtest.utils.compat import decode_path
import airtest.report.report as R

HTML_FILE = "log.html"
HTML_TPL = "log_template.html"
STATIC_DIR = os.path.dirname(R.__file__)

def get_parger(ap):
    ap.add_argument("script", help="script filepath")
    ap.add_argument("--outfile", help="output html filepath, default to be log.html")
    ap.add_argument("--static_root", help="static files root dir")
    ap.add_argument("--log_root", help="log & screen data root dir, logfile should be log_root/log.txt")
    ap.add_argument("--record", help="custom screen record file path", nargs="+")
    ap.add_argument("--export", help="export a portable report dir containing all resources")
    ap.add_argument("--lang", help="report language", default="en")
    ap.add_argument("--plugins", help="load reporter plugins", nargs="+")
    return ap


def get_script_info(script_path):
    script_name = os.path.basename(script_path)
    result_json = {"name": script_name, "author": None, "title": script_name, "desc": None}
    return json.dumps(result_json)


def _make_export_dir(self):
    dirpath = self.script_root
    logpath = self.script_root
    # copy static files
    for subdir in ["css", "fonts", "image", "js"]:
        dist = os.path.join(dirpath, "static", subdir)
        shutil.rmtree(dist, ignore_errors=True)
        self.copy_tree(os.path.join(STATIC_DIR, subdir), dist)

    return dirpath, logpath


def report(self, template_name, output_file=None, record_list=None):
    """替換LogToHtml中的report方法"""
    self._load()
    steps = self._analyse()
    # 修改info獲取方式
    info = json.loads(get_script_info(self.script_root))

    if self.export_dir:
        self.script_root, self.log_root = self._make_export_dir()
        output_file = os.path.join(self.script_root, HTML_FILE)
        self.static_root = "static/"

    if not record_list:
        record_list = [f for f in os.listdir(self.log_root) if f.endswith(".mp4")]
    records = [os.path.join(self.log_root, f) for f in record_list]

    if not self.static_root.endswith(os.path.sep):
        self.static_root = self.static_root.replace("\\", "/")
        self.static_root += "/"

    data = {}
    data['steps'] = steps
    data['name'] = os.path.basename(self.script_root)
    data['scale'] = self.scale
    data['test_result'] = self.test_result
    data['run_end'] = self.run_end
    data['run_start'] = self.run_start
    data['static_root'] = self.static_root
    data['lang'] = self.lang
    data['records'] = records
    data['info'] = info

    return self._render(template_name, output_file, **data)


def get_result(self):
    return self.test_result


def main(args):
    # script filepath
    path = decode_path(args.script)
    record_list = args.record or []
    log_root = decode_path(args.log_root) or path
    static_root = args.static_root or STATIC_DIR
    static_root = decode_path(static_root)
    export = decode_path(args.export) if args.export else None
    lang = args.lang if args.lang in ['zh', 'en'] else 'zh'
    plugins = args.plugins

    # gen html report
    rpt = R.LogToHtml(path, log_root, static_root, export_dir=export, lang=lang, plugins=plugins)
    # override methods
    rpt._make_export_dir = types.MethodType(_make_export_dir, rpt)
    rpt.report = types.MethodType(report, rpt)
    rpt.get_result = types.MethodType(get_result, rpt)

    rpt.report(HTML_TPL, output_file=args.outfile, record_list=record_list)

    return rpt.get_result()


if __name__ == "__main__":
    import argparse
    ap = argparse.ArgumentParser()
    args = get_parger(ap).parse_args()
    basedir = os.path.dirname(os.path.realpath(__file__))
    logdir = os.path.realpath(args.script)

    # 聚合結果
    results = []

    # 遍歷所有日志
    for subdir in os.listdir(logdir):
        if os.path.isfile(os.path.join(logdir, subdir)):
            continue
        args.script = os.path.join(logdir, subdir)
        args.outfile = os.path.join(args.script, HTML_FILE)
        result = {}
        result["name"] = subdir
        result["result"] = main(args)
        results.append(result)

    # 生成聚合報告
    env = jinja2.Environment(
        loader=jinja2.FileSystemLoader(basedir),
        extensions=(),
        autoescape=True
    )
    print("path: ",basedir)
    template = env.get_template("summary_template.html",basedir)
    html = template.render({"results": results})

    output_file = os.path.join(logdir, "summary.html")
    with io.open(output_file, 'w', encoding="utf-8") as f:
        f.write(html)
    print(output_file)

 

最終實現過程:

1. 外包測試人員通過airTest的IDE錄制腳本用例文件.air, 放入到測試服務器指定的  用例集  目錄下

2. 執行測試,生成聚合測試報告

3. 分析,並不斷優化。(最好是結合jekins做一個持續集成的閉環)

4. 期待airTest有更好的開源功能

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM