├── .gitattributes
├── img
├── 1.png
├── 2.png
├── 3.png
├── 4.gif
├── 5.gif
├── 5.png
├── 6.png
├── 7.png
└── 8.png
├── changelog.md
├── test_screenshot_appium.py
├── README.md
├── .gitignore
├── test_screenshot_selenium.py
└── HTMLTestRunner_cn.py
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.py linguist-language=Python
2 | *.html linguist-language=Python
--------------------------------------------------------------------------------
/img/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoverSky/HTMLTestRunner_cn/HEAD/img/1.png
--------------------------------------------------------------------------------
/img/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoverSky/HTMLTestRunner_cn/HEAD/img/2.png
--------------------------------------------------------------------------------
/img/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoverSky/HTMLTestRunner_cn/HEAD/img/3.png
--------------------------------------------------------------------------------
/img/4.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoverSky/HTMLTestRunner_cn/HEAD/img/4.gif
--------------------------------------------------------------------------------
/img/5.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoverSky/HTMLTestRunner_cn/HEAD/img/5.gif
--------------------------------------------------------------------------------
/img/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoverSky/HTMLTestRunner_cn/HEAD/img/5.png
--------------------------------------------------------------------------------
/img/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoverSky/HTMLTestRunner_cn/HEAD/img/6.png
--------------------------------------------------------------------------------
/img/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoverSky/HTMLTestRunner_cn/HEAD/img/7.png
--------------------------------------------------------------------------------
/img/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoverSky/HTMLTestRunner_cn/HEAD/img/8.png
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | # changelog
2 |
3 | + 20170925
4 | - 测试报告完全汉化,包括错误日志的中文处理
5 | - 针对selenium UI测试增加失败自动截图功能,截图自动轮播
6 | - 增加失败自动重试功能
7 | - 增加饼图统计
8 | - 同时兼容python2.x 和3.x
9 | + 20180402
10 | - 表格样式优化
11 | - 修复部分bug
12 | - 增加截图组,可展示多张截图,首次打开自动播放
13 | - 增加仅展示最后一次运行结果,多次重试时,每个测试用例仅展示一次
14 | + 20181213
15 | - 增加分类标签、通过率等,优化样式
16 | - 修复部分框架在SetUP中失败导致测试中断的问题导致 ErrorHandle的问题
17 | - 修复部分编码Bug
18 | - 优化运行逻辑
19 | - 对js代码优化,修复部分多次运行run导致结果异常的bug
20 |
21 | + 20200427
22 | - 修复页面小错误 (fzk27)
23 |
24 | + 20200508
25 | - 开放跳过测试的统计,完善饼图统计
--------------------------------------------------------------------------------
/test_screenshot_appium.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # @Time : 2017/9/6 11:26
3 | # @File : aaa.py
4 | # @Author : 守望@天空~
5 | """HTMLTestRunner 截图版示例 appium版"""
6 | from appium import webdriver
7 | import unittest
8 | from HTMLTestRunner_cn import HTMLTestRunner
9 |
10 |
11 | class case_01(unittest.TestCase):
12 |
13 | @classmethod
14 | def setUpClass(cls):
15 | desired_caps = {}
16 | desired_caps['platformName'] = 'Android'
17 | desired_caps['platformVersion'] = '4.4.2'
18 | desired_caps['deviceName'] = 'Android Emulator'
19 | desired_caps['app'] = 'com.tencent.mobileqq'
20 | desired_caps['appActivity'] = 'com.tencent.mobileqq.activity.SplashActivity'
21 | cls.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
22 |
23 | @classmethod
24 | def tearDownClass(cls):
25 | cls.driver.quit()
26 |
27 |
28 | def add_img(self):
29 | # 在是python3.x 中,如果在这里初始化driver ,因为3.x版本 unittest 运行机制不同,会导致用力失败时截图失败
30 | self.imgs.append(self.driver.get_screenshot_as_base64())
31 | return True
32 |
33 | def setUp(self):
34 | self.imgs = []
35 | self.addCleanup(self.cleanup)
36 |
37 | def cleanup(self):
38 | pass
39 |
40 |
41 | def test_case1(self):
42 | """ 手机QQ截图"""
43 | self.add_img()
44 | self.add_img()
45 | self.add_img()
46 | self.add_img()
47 | self.add_img()
48 |
49 |
50 |
51 | if __name__ == "__main__":
52 | suite = unittest.TestLoader().loadTestsFromTestCase(case_01)
53 | runer = HTMLTestRunner(title="带截图的测试报告", description="小试牛刀", stream=open("sample_test_report_appium.html", "wb"), verbosity=2, retry=1, save_last_try=True)
54 | runer.run(suite)
55 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HTMLTestRunner 汉化版
2 | 在原版的基础上进行扩展和改造
3 |
4 | # 当年改造初衷
5 | + 方便自己做汉化报告生成
6 | + 对自己积累知识的检验
7 | + 挑战下单文件报告都能做出什么花样
8 | 近两年不怎么搞UI自动化了,项目就一直没怎么更新(pytest香啊😅)
9 |
10 | # todo
11 | + 多线程/多进程执行用例(数据统计逻辑要重新设计,还有兼容性问题😑)
12 | + UI 美化 (通过CDN集成一些成熟的js库~然后加5毛钱特效😜)
13 | + 与ddt的集成(目测基本就把源码收进来😏)
14 |
15 |
16 |
17 | # 报告汉化,错误日志
18 | 
19 | # selenium/appium 截图
20 | 截图功能根据测试结果,当结果为fail或error时自动截图
21 | 截图方法在_TestResult 的测试结果收集中,报告使用的截图全部保存为base64编码,避免了报告图片附件的问题,可以根据自己使用的框架不同自行调整,selenium 使用的是get_screenshot_as_base64 方法获取页面截图的base64编码
22 | 
23 | 因为要提取用例中的driver变量获取webdriver对象,所以要实现截图功能必须定义在用例中定义webdriver 为driver
24 | ```python
25 | def setUp(self):
26 | self.imgs=[] # (可选)初始化截图列表
27 | self.driver = webdriver.Chrome()
28 | ```
29 | 或者
30 | ```python
31 | @classmethod
32 | def setUpClass(cls):
33 | cls.driver = webdriver.Chrome()
34 | ```
35 | 也可以在测试过程中某一步骤自定义添加截图,比如
36 | 
37 | 生成报告后会统一进行展示
38 | **Selenium截图轮播效果**
39 | 
40 | **Appium效果轮播截图**
41 | 
42 | # 用例失败重试
43 | 根据unittest的运行机制,在stopTest 中判断测试结果,如果失败或出错status为1,判断是否需要重试;
44 | 
45 |
46 | 在实例化HTMLTestRunner 对象时追加参数,retry,指定重试次数,如果save_last_try 为True ,一个用例仅显示最后一次测试的结果。
47 | ```python
48 | HTMLTestRunner(title="带截图的测试报告", description="小试牛刀", stream=open("sample_test_report.html", "wb"), verbosity=2, retry=2, save_last_try=True)
49 | ```
50 |
51 | 
52 | 如果save_last_try 为False,则显示所有重试的结果。
53 | ```python
54 | HTMLTestRunner(title="带截图的测试报告", description="小试牛刀", stream=open("sample_test_report.html", "wb"), verbosity=2, retry=2, save_last_try=False)
55 | ```
56 |
57 | 
58 | 运行中输出效果如下:
59 | 
60 |
61 | `注意:在python3 中因为unittest运行机制变动,在使用setUp/tearDown中初始化/退出driver时,会出现用例执行失败没有截图的问题,所以推荐使用样例中setUpClass/tearDownClass的用法`
62 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Python template
3 | # Byte-compiled / optimized / DLL files
4 | __pycache__/
5 | *.py[cod]
6 | *$py.class
7 |
8 | # C extensions
9 | *.so
10 | # Distribution / packaging
11 | .Python
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | pip-wheel-metadata/
25 | share/python-wheels/
26 | *.egg-info/
27 | .installed.cfg
28 | *.egg
29 | MANIFEST
30 |
31 | # PyInstaller
32 | # Usually these files are written by a python script from a template
33 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
34 | *.manifest
35 | *.spec
36 |
37 | # Installer logs
38 | pip-log.txt
39 | pip-delete-this-directory.txt
40 |
41 | # Unit test / coverage reports
42 | htmlcov/
43 | .tox/
44 | .nox/
45 | .coverage
46 | .coverage.*
47 | .cache
48 | nosetests.xml
49 | coverage.xml
50 | *.cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 |
63 | # Flask stuff:
64 | instance/
65 | .webassets-cache
66 |
67 | # Scrapy stuff:
68 | .scrapy
69 |
70 | # Sphinx documentation
71 | docs/_build/
72 |
73 | # PyBuilder
74 | target/
75 |
76 | # Jupyter Notebook
77 | .ipynb_checkpoints
78 |
79 | # IPython
80 | profile_default/
81 | ipython_config.py
82 |
83 | # pyenv
84 | .python-version
85 |
86 | # pipenv
87 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
88 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
89 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
90 | # install all needed dependencies.
91 | #Pipfile.lock
92 |
93 | # celery beat schedule file
94 | celerybeat-schedule
95 |
96 | # SageMath parsed files
97 | *.sage.py
98 |
99 | # Environments
100 | .env
101 | .venv
102 | env/
103 | venv/
104 | ENV/
105 | env.bak/
106 | venv.bak/
107 |
108 | # Spyder project settings
109 | .spyderproject
110 | .spyproject
111 |
112 | # Rope project settings
113 | .ropeproject
114 |
115 | # mkdocs documentation
116 | /site
117 |
118 | # mypy
119 | .mypy_cache/
120 | .dmypy.json
121 | dmypy.json
122 |
123 | # Pyre type checker
124 | .pyre/
125 |
126 | .idea/*
127 | /.idea/*
128 | Untitled.ipynb
129 | /.ipynb_checkpoints/
130 |
--------------------------------------------------------------------------------
/test_screenshot_selenium.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # @Time : 2017/9/6 11:26
3 | # @File : aaa.py
4 | # @Author : 守望@天空~
5 | """HTMLTestRunner 截图版示例 selenium 版"""
6 | from selenium import webdriver
7 | import unittest
8 | import time
9 | from HTMLTestRunner_cn import HTMLTestRunner
10 | import sys
11 |
12 |
13 | class case_01(unittest.TestCase):
14 | """
15 | def setUp(cls):
16 | cls.driver = webdriver.Chrome()
17 |
18 | def tearDown(cls):
19 | cls.driver.quit()
20 |
21 | """
22 | @classmethod
23 | def setUpClass(cls):
24 | cls.driver = webdriver.Chrome()
25 |
26 | @classmethod
27 | def tearDownClass(cls):
28 | cls.driver.quit()
29 |
30 | def add_img(self):
31 | # self.imgs.append(self.driver.get_screenshot_as_base64())
32 | return True
33 |
34 | def setUp(self):
35 | # 在python3.x 中,如果在这里初始化driver ,因为3.x版本 unittest 运行机制不同,会导致用例失败后截图失败
36 | self.imgs = []
37 | self.addCleanup(self.cleanup)
38 |
39 | def cleanup(self):
40 | pass
41 |
42 |
43 | def test_case1(self):
44 | """ 百度搜索
45 | 呵呵呵呵
46 | """
47 | print("本次校验没过?")
48 | print ("超级长"*66)
49 | self.driver.get("https://www.baidu.com")
50 | self.add_img()
51 | self.driver.find_element_by_id('kw').send_keys(u'百度一下')
52 | self.add_img()
53 | self.driver.find_element_by_id('su').click()
54 | time.sleep(1)
55 | self.add_img()
56 |
57 | def test_case2(self):
58 | """搜狗首页"""
59 | self.driver.get("http://www.sogou.com")
60 | print("本次校验没过?")
61 | self.assertTrue(False,"这是相当的睿智了")
62 |
63 | def test_case3(self):
64 | """ QQ邮箱"""
65 | self.driver.get("https://mail.qq.com")
66 | # self.imgs.append(self.driver.get_screenshot_as_base64())
67 | print("没法打印?")
68 | self.assertIn(u"中文", u'中华','小当家?')
69 |
70 | def test_case4(self):
71 | u""" 淘宝"""
72 | self.driver.get("http://www.taobao.com/")
73 | raise Exception
74 | self.add_img()
75 | self.assertTrue(True)
76 |
77 |
78 | class case_02(unittest.TestCase):
79 | """
80 | def setUp(cls):
81 | cls.driver = webdriver.Chrome()
82 |
83 | def tearDown(cls):
84 | cls.driver.quit()
85 |
86 | """
87 | @classmethod
88 | def setUpClass(cls):
89 | cls.driver = webdriver.Chrome()
90 |
91 | @classmethod
92 | def tearDownClass(cls):
93 | cls.driver.quit()
94 |
95 | def add_img(self):
96 | # self.imgs.append(self.driver.get_screenshot_as_base64())
97 | return True
98 |
99 | def setUp(self):
100 | # 在是python3.x 中,如果在这里初始化driver ,因为3.x版本 unittest 运行机制不同,会导致用力失败时截图失败
101 | self.imgs = []
102 | self.addCleanup(self.cleanup)
103 |
104 | def cleanup(self):
105 | pass
106 |
107 |
108 | def test_case1(self):
109 | """ 百度搜索
110 | 呵呵呵呵
111 | """
112 | print("校验了一下")
113 | self.driver.get("https://www.baidu.com")
114 | self.add_img()
115 | self.driver.find_element_by_id('kw').send_keys(u'百度一下')
116 | self.add_img()
117 | self.driver.find_element_by_id('su').click()
118 | time.sleep(1)
119 | self.add_img()
120 |
121 | @unittest.skip('跳过')
122 | def test_case2(self):
123 | """搜狗首页"""
124 | self.driver.get("http://www.sogou.com")
125 | print("本次校验没过?")
126 | self.assertTrue(False,"这是相当的睿智了")
127 |
128 | def test_case3(self):
129 | """ QQ邮箱"""
130 | self.driver.get("https://mail.qq.com")
131 | # self.imgs.append(self.driver.get_screenshot_as_base64())
132 | print("没法打印?")
133 | self.assertIn(u"中文", u'中文')
134 |
135 | def test_case4(self):
136 | u""" 淘宝"""
137 | self.driver.get("http://www.taobao.com/")
138 | self.add_img()
139 | self.assertTrue(True)
140 |
141 |
142 | if __name__ == "__main__":
143 | from unittest import TestResult
144 | suite1 = unittest.TestLoader().loadTestsFromTestCase(case_01)
145 | suite2 = unittest.TestLoader().loadTestsFromTestCase(case_02)
146 | suites = unittest.TestSuite()
147 | suites.addTests([suite1,suite2])
148 |
149 | runer = HTMLTestRunner(title="带截图的测试报告", description="小试牛刀", stream=open("sample_test_report.html", "wb"), verbosity=2, retry=2, save_last_try=True)
150 | runer.run(suites)
151 |
--------------------------------------------------------------------------------
/HTMLTestRunner_cn.py:
--------------------------------------------------------------------------------
1 | #-*- coding: utf-8 -*-
2 | """
3 | A TestRunner for use with the Python unit testing framework. It
4 | generates a HTML report to show the result at a glance.
5 |
6 | The simplest way to use this is to invoke its main method. E.g.
7 |
8 | import unittest
9 | import HTMLTestRunner
10 |
11 | ... define your tests ...
12 |
13 | if __name__ == '__main__':
14 | HTMLTestRunner.main()
15 |
16 |
17 | For more customization options, instantiates a HTMLTestRunner object.
18 | HTMLTestRunner is a counterpart to unittest's TextTestRunner. E.g.
19 |
20 | # output to a file
21 | fp = file('my_report.html', 'wb')
22 | runner = HTMLTestRunner.HTMLTestRunner(
23 | stream=fp,
24 | title='My unit test',
25 | description='This demonstrates the report output by HTMLTestRunner.'
26 | )
27 |
28 | # Use an external stylesheet.
29 | # See the Template_mixin class for more customizable options
30 | runner.STYLESHEET_TMPL = ''
31 |
32 | # run the test
33 | runner.run(my_test_suite)
34 |
35 |
36 | ------------------------------------------------------------------------
37 | Copyright (c) 2004-2007, Wai Yip Tung
38 | All rights reserved.
39 |
40 | Redistribution and use in source and binary forms, with or without
41 | modification, are permitted provided that the following conditions are
42 | met:
43 |
44 | * Redistributions of source code must retain the above copyright notice,
45 | this list of conditions and the following disclaimer.
46 | * Redistributions in binary form must reproduce the above copyright
47 | notice, this list of conditions and the following disclaimer in the
48 | documentation and/or other materials provided with the distribution.
49 | * Neither the name Wai Yip Tung nor the names of its contributors may be
50 | used to endorse or promote products derived from this software without
51 | specific prior written permission.
52 |
53 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
54 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
55 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
56 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
57 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
58 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
59 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
60 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
61 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
62 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 | """
65 |
66 | # URL: http://tungwaiyip.info/software/HTMLTestRunner.html
67 |
68 | __author__ = "Wai Yip Tung"
69 | __version__ = "0.8.3"
70 |
71 |
72 | """
73 | Change History
74 | Version 0.8.4 by GoverSky
75 | * Add sopport for 3.x
76 | * Add piechart for resultpiechart
77 | * Add Screenshot for selenium_case test
78 | * Add Retry on failed
79 |
80 | Version 0.8.3
81 | * Prevent crash on class or module-level exceptions (Darren Wurf).
82 |
83 | Version 0.8.2
84 | * Show output inline instead of popup window (Viorel Lupu).
85 |
86 | Version in 0.8.1
87 | * Validated XHTML (Wolfgang Borgert).
88 | * Added description of test classes and test cases.
89 |
90 | Version in 0.8.0
91 | * Define Template_mixin class for customization.
92 | * Workaround a IE 6 bug that it does not treat
419 | %(heading)s
420 |