Appium 粗暴解决 HTMLTestRunner 加入截图展示功能

hanzo · 2016年04月13日 · 最后由 肖静远 回复于 2017年06月16日 · 5964 次阅读

最近使用 appium+python 来做自动化,测试报告用的网上共享的 HTMLTestRunner 模块,但是里面貌似没有展示截图的功能,于是自己动手稍微修改了一下!
先上成果图,点击图片名字就能打开图片

总体思路为:在 HTMLTestRunner 的 report 模板中加入一列 picture,然后将用来展示图片的 html 打印到每个 case 的日志中,再从日志中将这段文字截取出来放入 report 中(主要是为了简单粗暴的将每个 case 与相关截图正确对应起来~想不到其他办法啦!欢迎高手们给出更加简单快捷的办法~)
以下为我的操作方法,有点长~
一、在 HTMLTestRunner.py 里的原有的 html 表格中插入了一列 picture(在

View下面加入一行Picture,在 下加入一行即可),用来展示脚本中的截图超链接
<tr id='header_row'>
    <td>Test Group/Test case</td>
    <td>Count</td>
    <td>Pass</td>
    <td>Fail</td>
    <td>Error</td>
    <td>View</td>
    <td>Picture</td>
</tr>
%(test_list)s
<tr id='total_row'>
    <td>Total</td>
    <td>%(count)s</td>
    <td>%(Pass)s</td>
    <td>%(fail)s</td>
    <td>%(error)s</td>
    <td>&nbsp;</td>
    <td><a href="" target="_blank"></a></td>
</tr>
</table>

二、还是在 HTMLTestRunner.py 里插入一行%(html) s 来放置对应脚本的截图

    REPORT_TEST_WITH_OUTPUT_TMPL = r"""
<tr id='%(tid)s' class='%(Class)s'>
    <td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
    <td colspan='5' align='center'>

    <!--css div popup start-->
    <a class="popup_link" onfocus='this.blur();' href="javascript:showTestDetail('div_%(tid)s')" >
        %(status)s</a>

    <div id='div_%(tid)s' class="popup_window">
        <div style='text-align: right; color:red;cursor:pointer'>
        <a onfocus='this.blur();' onclick="document.getElementById('div_%(tid)s').style.display = 'none' " >
           [x]</a>
        </div>
        <pre>
        %(script)s
        </pre>
    </div>
    <!--css div popup end-->

    </td>
    %(html)s
</tr>

三、依然在 HTMLTestRunner.py 中,_generate_report_test() 函数中,插入 html 的内容,因为本身初学者,对 unittest 和 htmltestrunner 都不怎么了解,观察 htmltestrunner 的报告发现它能展示脚本执行过程中打印的 log 文本,所以我强行把自己组装的用于展示图片 html 代码打印到执行日志中,然后通过关键字截取出来,放置在 script 后面的位置,也就是刚才新建的 picture 列(要是觉得最后 report 中打印的 log 中加入了这段 html 影响美观,可以在下面代码中 script 里删掉~我懒得写了~)

script = self.REPORT_TEST_OUTPUT_TMPL % dict(
    id = tid,
    output = saxutils.escape(uo+ue),
)

s = uo+ue
html = s[s.find('htmlbegin')+9:s.find('htmlend')]

row = tmpl % dict(
    tid = tid,
    Class = (n == 0 and 'hiddenRow' or 'none'),
    style = n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'none'),
    desc = desc,
    script = script,
    html = html,
    status = self.STATUS[n],
)

四、在自己封装的手机截屏方法中加入分别将截图名称和截图存放路径插入对应的数组中(也可以使用二维数组),以下分别为打印日志,截屏,组装 html 的方法,在组装完成的 html 代码开头和结尾分别叫上 htmlbegin 和 htmlend 作为之后截取使用的关键字

# _*_ coding:utf-8 _*_
__author__ = 'gjj14453'
import logging
import os
import common.myDate as myDate


PATH = lambda p: os.path.abspath(
    os.path.join(os.path.dirname(__file__), p))


pics = []
picpath = []


##################################
#  日志
# 0: debug
# 1:info
# 2:warning
# -1:error
###################################
def mylogger(msg, flag=1):
    logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(filename)s %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename='mylog.log',
                    filemode='w')
    console = logging.StreamHandler()
    console.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
    console.setFormatter(formatter)
    logging.getLogger('').addHandler(console)
    if flag == 0:
        logging.debug(msg)
    elif flag == 1:
        logging.info(msg)
    elif flag == 2:
        logging.warning(msg)
        screenshot()
    elif flag == -1:
        logging.error(msg)
        screenshot()
    logging.getLogger('').removeHandler(console)


#  截屏
def screenshot():
    dirname = PATH('D:\\MyConfiguration\\gjj14453\\PycharmProjects\\untitled\\list_out' + "/screenshot")
    os.popen("adb wait-for-device")
    os.popen("adb shell screencap -p /data/local/tmp/tmp.png")
    if not os.path.isdir(dirname):
        os.makedirs(dirname)
    pic = myDate.timestampname() + ".png"
    path = dirname + "/" + pic
    os.popen("adb pull /data/local/tmp/tmp.png " + PATH(path))
    os.popen("adb shell rm /data/local/tmp/tmp.png")
    mylogger("截图为:" + pic)
    pics.append(pic)
    picpath.append(path)


def creathtml(path, pic):
    html = ''
    if range(len(path)) > 0:
        for i in range(len(path)):
            if i == 0:
                html = '<a href=' + path[i] + ' target="_blank">' + pic[i] + '</a>'
            else:
                html = html + '<br /><a href=' + path[i] + ' target="_blank">' + pic[i] + '</a>'
    else:
        html = ''
    htmls = 'htmlbegin<td>' + html +'</td>htmlend'
    return htmls

五、之后在 case 中加入打印 html 到日志中的语句就 OK 啦

class Test(unittest.TestCase):

    def setUp(self):
        log.picpath = []
        log.pics = []
        pass

    def tearDown(self):
        pass

    def test(self):
        log.mylogger('aaa', -1)
        log.mylogger('bbb', -1)
        log.mylogger(log.creathtml(log.picpath, log.pics))

最后,还是希望有高手能给我一个更加简单的插入对应截图的办法~本来想把截图存放的数组传到脚本执行的 result 中再一一提取,试了几次毫无成果~

共收到 34 条回复 时间 点赞

赞一个

赞一个

3楼 已删除

想请教下,最后这个 html 还需要在哪里添加吗 我参照你这样写的 截图那一栏是空白的

#4 楼 @happy_summer 看看是不是步骤二没有加入截图的 html~

想请教一下你,你这个截图是安卓的,如果苹果的话,怎么弄呢

#5 楼 @hanzo000 想请教下,最后这个 html 还需要在哪里添加吗 我参照你这样写的 截图那一栏是空白的
#4 楼 @happy_summer 请问你解决了么这个问题

最近又优化了一下,截图插入到了断言源码中,#7 楼 @mads 要不留个地址,我把我修改过的文件发给你?

#8 楼 @hanzo000 79523822@qq.com 好人一生平安

楼主,有个疑惑希望你解答一下。请问你是在哪里调用的 HTMLTestRunner 的呢?因为我用的不是 appium,所以如果问题有点小白,请见谅

#10 楼 @YellowStarr 你 selenium 也可以调用的,python 里 import HTMLTestRunner

谁发个修改后的给我呢? 779140143@qq.com

赞,看了一下 htmltestrunner 源码试了一下发现 lz 的思路实在太清晰改的太棒了。
不过我也是有点自己的看法,你目前的做法是要调用了 mylogger 方法才会有那些操作,那实际跑 case 的时候错在哪里是无法控制的,所以我目前就不管 case 是否 fail 都在 teardown 里面截屏一下保存,这样虽然成功的 case 有不必要的截屏,不过可以确保 fail 的 case 一定是在失败的地方截屏了。要做到只在跑出 error 的地方截屏估计要直接改 logging 模块了吧。
还有就是你的那个问题,我是觉得照道理一个 case 应该是只有一个验证点吧,本来就一个 case 对应一个方法粒度很小了,不太需要一个 case 还截屏多次这种情况。

大神发一个修改后的版本给小菜鸟学习学习吧😍 924940668@qq.com

同求修改后的版本 hezhenpan@163.com 感激不尽

求大神再密我一下

同求修改后的断言中的版本 693055797@qq.com

匿名 #18 · 2016年07月15日

#8 楼 @hanzo000求修改后的版本 626948487@qq.com

#18 楼 @riwater 我有他 qq

@hanzo000 能否发我一份?954324919@qq.com

@hanzo000 能否留个联系方式,有 webview 相关的问题想和你讨论一下

22楼 已删除

6666666

求修改后的版本,谢谢 470360455@qq.com

非常好,可以学习下

你好,我最近也在正在 UI 自动化测试,遇到的问题和你一样,想用网上 HTMLTestRunner 改装下,能不能把你改后的代码发我一份。感激。xiexinxi@126.com

大神,写的不错,很赞,能否给我发份 wubingfen521@163.com

同求源码 765588260@qq.com 感谢大神了

遇到了一样的问题,想自己在 teardown 里面加个截图,但是不知道怎么整合到报告中。
源码求一份学习 124732156@qq.com

厉害了 word 哥

自己按照上面的方法写,代码跑总是有各种问题。可以分享一下源码吗?m170587788@163.com

@hanzo000 麻烦大神发一下哈:1258673037@qq.com


楼主这一堆 日志如何去掉呀?

291008572@qq.com 求发求改后版本

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册