diff --git a/README.md b/README.md index 5deb578..1c55044 100755 --- a/README.md +++ b/README.md @@ -295,6 +295,34 @@ ATX毕竟是一个python库,给出代码的例子可能更好理解一些 # out: HookEvent(flag=8, args=(), kwargs={}) ``` +## 生成测试报告 +注:该功能还不完善,因为部分URL没有改掉,所有外网用户还不能使用 + +### Usage +```py +import atx +from atx.ext import report # report lib + + +d = d.connect() +report.listen(d, save_dir='report') +d.click(200, 200) +``` + +After done, HTML report will be saved to report dir. with such directory + +``` +report/ + |-- index.html + `-- images/ + |-- before_123123123123.png + |-- ... +``` + +open `index.html` with browser. + +![report](docs/report.png) + ## 命令行工具 为了方便测试以及开发,atx封装了很多的命令行工具 diff --git a/atx/cmds/run.py b/atx/cmds/run.py index 2010d0e..f7748d4 100644 --- a/atx/cmds/run.py +++ b/atx/cmds/run.py @@ -14,23 +14,33 @@ import subprocess32 as subprocess -CONFIG_FILE = 'atx.yml' - - def json2obj(data): return json.loads(json.dumps(data), object_hook=lambda d: Namespace(**d)) +def must_exec(*cmds, **kwargs): + shell = kwargs.get('shell', False) + cmdline = cmds[0] if shell else subprocess.list2cmdline(cmds) + ret = os.system(cmdline) + if ret != 0: + raise SystemExit("Execute '%s' error" % cmdline) + + def install(src): - print src + must_exec('python', '-matx', 'install', src) def runtest(scripts): - print scripts + for script in scripts: + must_exec(script, shell=True) def notify_popo(users, message): - print users, message + print 'Skip, todo' + for user in users: + pass + # maybe should not put code here + # print users, message def main(config_file): @@ -40,19 +50,20 @@ def main(config_file): with open(config_file, 'rb') as f: cfg = json2obj(yaml.load(f)) - if hasattr(cfg, 'installation'): - install(cfg.installation) - - if hasattr(cfg, 'script'): - if isinstance(cfg.script, basestring): - scripts = [cfg.script] - else: - scripts = cfg.script - runtest(scripts) - - if hasattr(cfg, 'notification'): - if hasattr(cfg.notification, 'popo'): - notify_popo(cfg.notification.popo, 'hi') + try: + if hasattr(cfg, 'installation'): + install(cfg.installation) + + if hasattr(cfg, 'script'): + if isinstance(cfg.script, basestring): + scripts = [cfg.script] + else: + scripts = cfg.script + runtest(scripts) + finally: + if hasattr(cfg, 'notification'): + if hasattr(cfg.notification, 'popo'): + notify_popo(cfg.notification.popo, 'hi') if __name__ == '__main__': diff --git a/atx/ext/index.tmpl.html b/atx/ext/index.tmpl.html new file mode 100644 index 0000000..3983320 --- /dev/null +++ b/atx/ext/index.tmpl.html @@ -0,0 +1,268 @@ + + + + + + + + + Atx Web IDE + + + + + + + + + +
+
+
+ 基本信息 +
+
+
+
    +
  • SerialNo{{device.serial}}
  • +
  • Brand{{device.product_brand}}
  • +
  • StepCount{{step_count}}
  • +
+
+
+
    +
  • Display{{device.display.width}}x{{device.display.height}}
  • +
  • + Result + {{test_result ? "PASS": "FAIL"}} +
  • +
+
+
+
+ +
+
+
+ $ + {{step.time}}s {{step.action}} +
+
+ + + + +
+
+
+ +
+

Make the mobile game test automated, release QAers from the repeated work.

+ +
+
+ + + + + + + + + + + + diff --git a/atx/ext/report.py b/atx/ext/report.py new file mode 100644 index 0000000..acbb534 --- /dev/null +++ b/atx/ext/report.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import atexit +import os +import time +import json + +from atx import consts + + +__dir__ = os.path.dirname(os.path.abspath(__file__)) + +def listen(d, save_dir='report'): + image_dir = os.path.join(save_dir, 'images') + if not os.path.exists(image_dir): + os.makedirs(image_dir) + + steps = [] + w, h = d.display + if d.rotation in (1, 3): # for horizontal + w, h = h, w + result = dict(device=dict( + display=dict(width=w, height=h), + serial=d.serial, + ), steps=steps) + start_time = time.time() + + def listener(evt): + if evt.flag == consts.EVENT_CLICK: + screen_before = 'images/before_%d.png' % time.time() + screen_before_abspath = os.path.join(save_dir, screen_before) + d.last_screenshot.save(screen_before_abspath) + screen_after = 'images/after_%d.png' % time.time() + d.screenshot(os.path.join(save_dir, screen_after)) + + (x, y) = evt.args + steps.append({ + 'time': '%.1f' % (time.time()-start_time,), + 'action': 'click', + 'screen_before': screen_before, + 'screen_after': screen_after, + 'position': {'x': x, 'y': y}, + 'success': True, + }) + + # print 'EVENT:', evt + + d.add_listener(listener, consts.EVENT_ALL ^ consts.EVENT_SCREENSHOT) + + def on_finish(): + data = json.dumps(result) + tmpl_path = os.path.join(__dir__, 'index.tmpl.html') + save_path = os.path.join(save_dir, 'index.html') + + with open(tmpl_path) as f: + html_content = f.read().replace('$$data$$', data) + + with open(save_path, 'wb') as f: + f.write(html_content) + + atexit.register(on_finish) \ No newline at end of file diff --git a/docs/report.png b/docs/report.png new file mode 100644 index 0000000..04ec44d Binary files /dev/null and b/docs/report.png differ