├── requirements.txt ├── .gitattributes ├── MANIFEST.in ├── img ├── style1.png ├── style2.png └── print_info.png ├── demo ├── __init__.py ├── testcase │ ├── battle │ │ ├── __init__.py │ │ └── test_tattle.py │ ├── chat │ │ ├── __init__.py │ │ └── test_chat.py │ ├── legion │ │ ├── __init__.py │ │ └── test_legion.py │ └── __init__.py ├── debug_case.py ├── use_report.py ├── run.py └── report │ └── 2019-03-13-18-46-13-style-1.html ├── utx ├── report │ ├── __init__.py │ └── style_1.py ├── __init__.py ├── tag.py ├── setting.py ├── log.py ├── runner.py └── core.py ├── LICENSE ├── .gitignore ├── setup.py └── README.md /requirements.txt: -------------------------------------------------------------------------------- 1 | colorama 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.html linguist-language=python -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include LICENSE 3 | include requirements.txt -------------------------------------------------------------------------------- /img/style1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jianbing/utx/HEAD/img/style1.png -------------------------------------------------------------------------------- /img/style2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jianbing/utx/HEAD/img/style2.png -------------------------------------------------------------------------------- /demo/__init__.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | 4 | 5 | -------------------------------------------------------------------------------- /img/print_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jianbing/utx/HEAD/img/print_info.png -------------------------------------------------------------------------------- /utx/report/__init__.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | """ 4 | Created by Administrator on 2019-03-12 5 | """ -------------------------------------------------------------------------------- /demo/testcase/battle/__init__.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | """ 4 | Created by jianbing on 2017-10-27 5 | """ -------------------------------------------------------------------------------- /demo/testcase/chat/__init__.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | """ 4 | Created by jianbing on 2017-10-27 5 | """ -------------------------------------------------------------------------------- /demo/testcase/legion/__init__.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | """ 4 | Created by jianbing on 2017-10-27 5 | """ -------------------------------------------------------------------------------- /demo/testcase/__init__.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | 4 | 5 | if __name__ == '__main__': 6 | pass 7 | 8 | -------------------------------------------------------------------------------- /utx/__init__.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | from utx.tag import Tag 4 | from utx import log 5 | from utx.setting import setting 6 | from utx.core import * 7 | from utx.runner import TestRunner 8 | -------------------------------------------------------------------------------- /demo/debug_case.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | 4 | import utx 5 | from demo.testcase.battle.test_tattle import TestBattle 6 | 7 | utx.run_case(TestBattle, "test_get_battle_reward") 8 | 9 | 10 | -------------------------------------------------------------------------------- /demo/use_report.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | """ 4 | 单独使用测试报告组件,不需要utx的其他扩展功能 5 | """ 6 | import utx 7 | 8 | if __name__ == '__main__': 9 | 10 | utx.stop_patch() 11 | 12 | runner = utx.TestRunner() 13 | runner.add_case_dir(r"testcase\chat") 14 | runner.run_test(report_title='接口自动化测试报告') -------------------------------------------------------------------------------- /utx/tag.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | """ 4 | 测试用例标签类 5 | """ 6 | 7 | from enum import Enum, unique 8 | 9 | 10 | class NewTag: 11 | def __init__(self, desc=""): 12 | self.desc = desc 13 | 14 | 15 | @unique 16 | class Tag(Enum): 17 | SMOKE = NewTag("冒烟") # 冒烟测试标记,可以重命名,不要删除 18 | ALL = NewTag("完整") # 完整测试标记,可以重命名,不要删除 19 | 20 | # 以下开始为扩展标签,自行调整 21 | V1_0_0 = NewTag("V1.0.0版本") 22 | V2_0_0 = NewTag("V2.0.0版本") 23 | 24 | -------------------------------------------------------------------------------- /demo/testcase/chat/test_chat.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | 4 | import unittest 5 | import utx 6 | 7 | 8 | class TestChat(unittest.TestCase): 9 | def test_chat_in_world_channel(self): 10 | """测试世界聊天 11 | 12 | :return: 13 | """ 14 | print("测试世界聊天") 15 | raise Exception("运行报错了") 16 | 17 | @unittest.skip("跳过此用例") 18 | def test_chat_in_personal_channel(self): 19 | """测试私聊 20 | 21 | :return: 22 | """ 23 | print("测试私聊") 24 | 25 | @utx.skip("跳过此用例") 26 | def test_chat_in_union_channel(self): 27 | """测试公会聊天 28 | 29 | :return: 30 | """ 31 | print("测试公会聊天") 32 | -------------------------------------------------------------------------------- /utx/setting.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | """ 4 | Created by jianbing on 2017-11-04 5 | """ 6 | from utx.tag import Tag 7 | 8 | 9 | class setting: 10 | # 只运行的用例类型 11 | run_case = {Tag.ALL} 12 | 13 | # 开启用例排序 14 | sort_case = True 15 | 16 | # 每个用例的执行间隔,单位是秒 17 | execute_interval = 0.1 18 | 19 | # 开启检测用例描述 20 | check_case_doc = True 21 | 22 | # 显示完整用例名字(函数名字+参数信息) 23 | full_case_name = False 24 | 25 | # 测试报告显示的用例名字最大程度 26 | max_case_name_len = 80 27 | 28 | # 执行用例的时候,显示报错信息 29 | show_error_traceback = True 30 | 31 | # 测试报告样式1 32 | create_report_by_style_1 = True 33 | 34 | # 测试报告样式2 35 | create_report_by_style_2 = True 36 | 37 | # 在控制台显示print打印的内容 38 | show_print_in_console = False 39 | -------------------------------------------------------------------------------- /demo/testcase/battle/test_tattle.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | 4 | import unittest 5 | from utx import * 6 | 7 | 8 | class TestBattle(unittest.TestCase): 9 | def test_start_battle(self): 10 | """测试开始战斗 11 | 12 | :return: 13 | """ 14 | print("测试开始战斗") 15 | 16 | def test_skill_buff(self): 17 | """测试技能buff 18 | 19 | :return: 20 | """ 21 | print("测试技能buff") 22 | 23 | @tag(Tag.V1_0_0) 24 | def test_normal_attack(self): 25 | """测试普通攻击 26 | 27 | :return: 28 | """ 29 | print("测试普通攻击") 30 | 31 | @data({"gold": 1000, "diamond": 100}, {"gold": 2000, "diamond": 200}, unpack=False) 32 | def test_get_battle_reward(self, reward): 33 | """ 测试领取战斗奖励 34 | 35 | :return: 36 | """ 37 | print(reward) 38 | print("测试领取战斗奖励,获得的钻石数量是:{}".format(reward['diamond'])) 39 | log.debug("测试领取战斗奖励,获得的钻石数量是:{}".format(reward['diamond'])) 40 | -------------------------------------------------------------------------------- /demo/run.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | 4 | from utx import * 5 | import logging 6 | 7 | if __name__ == '__main__': 8 | setting.run_case = {Tag.ALL} # 运行全部测试用例 9 | # setting.run_case = {Tag.SMOKE} # 只运行SMOKE标记的测试用例 10 | # setting.run_case = {Tag.SMOKE, Tag.V1_0_0} # 只运行SMOKE和V1_0_0标记的测试用例 11 | 12 | setting.check_case_doc = False # 关闭检测是否编写了测试用例描述 13 | setting.full_case_name = True 14 | setting.max_case_name_len = 80 # 测试报告内,显示用例名字的最大程度 15 | setting.show_error_traceback = True # 执行用例的时候,显示报错信息 16 | setting.sort_case = True # 是否按照编写顺序,对用例进行排序 17 | setting.create_report_by_style_1 = True # 测试报告样式1 18 | setting.create_report_by_style_2 = True # 测试报告样式2 19 | setting.show_print_in_console = True 20 | 21 | log.set_level(logging.DEBUG) # 设置utx的log级别 22 | # log.set_level_to_debug() # 设置log级别的另外一种方法 23 | 24 | runner = TestRunner() 25 | runner.add_case_dir(r"testcase") 26 | runner.run_test(report_title='接口自动化测试报告') 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2017] [jianbing.g] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /demo/testcase/legion/test_legion.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | 4 | import unittest 5 | from utx import * 6 | 7 | 8 | class TestLegion(unittest.TestCase): 9 | def setUp(self): 10 | print('运行setUp方法') 11 | 12 | def tearDown(self): 13 | print('运行tearDown方法') 14 | 15 | @tag(Tag.SMOKE) 16 | def test_create_legion(self): 17 | """测试创建军团 18 | 19 | :return: 20 | """ 21 | 22 | @tag(Tag.ALL) 23 | @data(["gold", 100], ["diamond", 500]) 24 | def test_bless(self, bless_type, cost): 25 | """测试公会祈福 26 | 27 | :param bless_type: 祈福类型 28 | :param cost: 消耗数量 29 | :return: 30 | """ 31 | print(bless_type) 32 | print(cost) 33 | 34 | @skip("跳过的原因") 35 | @data(10001, 10002, 10003) 36 | def test_receive_bless_box(self, box_id): 37 | """ 测试领取祈福宝箱 38 | 39 | :return: 40 | """ 41 | print(box_id) 42 | 43 | @tag(Tag.V1_0_0, Tag.ALL) 44 | def test_quit_legion(self): 45 | """测试退出军团 46 | 47 | :return: 48 | """ 49 | print("测试退出军团") 50 | assert 1 == 2 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Sphinx documentation 57 | docs/_build/ 58 | 59 | # PyBuilder 60 | target/ 61 | 62 | #Ipython Notebook 63 | .ipynb_checkpoints 64 | 65 | # pyenv 66 | .python-version 67 | 68 | # pycharm 69 | .idea/ 70 | 71 | # 本地测试 72 | local_test/ 73 | wxglade/ 74 | kivy-2014/ 75 | designer/ 76 | youtube_dl_gui/ 77 | 78 | 79 | # 本地配置 80 | local_config.py 81 | 82 | *.bak 83 | -------------------------------------------------------------------------------- /utx/log.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | """ 4 | Created by jianbing on 2017-10-30 5 | """ 6 | import sys 7 | import logging.handlers 8 | from colorama import Fore, Style 9 | 10 | _logger = logging.getLogger('utx') 11 | _logger.setLevel(logging.DEBUG) 12 | _handler = logging.StreamHandler(sys.stdout) 13 | _handler.setFormatter(logging.Formatter('%(asctime)s %(message)s')) 14 | _logger.addHandler(_handler) 15 | 16 | 17 | def debug(msg): 18 | _logger.debug("DEBUG " + str(msg)) 19 | 20 | 21 | def info(msg): 22 | _logger.info(Fore.GREEN + "INFO " + str(msg) + Style.RESET_ALL) 23 | 24 | 25 | def error(msg): 26 | _logger.error(Fore.RED + "ERROR " + str(msg) + Style.RESET_ALL) 27 | 28 | 29 | def warn(msg): 30 | _logger.warning(Fore.YELLOW + "WARNING " + str(msg) + Style.RESET_ALL) 31 | 32 | 33 | def _print(msg): 34 | _logger.debug(Fore.BLUE + "PRINT " + str(msg) + Style.RESET_ALL) 35 | 36 | 37 | def set_level(level): 38 | """ 设置log级别 39 | 40 | :param level: logging.DEBUG, logging.INFO, logging.WARN, logging.ERROR 41 | :return: 42 | """ 43 | _logger.setLevel(level) 44 | 45 | 46 | def set_level_to_debug(): 47 | _logger.setLevel(logging.DEBUG) 48 | 49 | 50 | def set_level_to_info(): 51 | _logger.setLevel(logging.INFO) 52 | 53 | 54 | def set_level_to_warn(): 55 | _logger.setLevel(logging.WARN) 56 | 57 | 58 | def set_level_to_error(): 59 | _logger.setLevel(logging.ERROR) 60 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import io 5 | import os 6 | import sys 7 | from shutil import rmtree 8 | from setuptools import setup, Command, find_packages 9 | 10 | NAME = 'utx' 11 | DESCRIPTION = '对Python unittest的功能进行了扩展' 12 | URL = 'https://github.com/jianbing/utx' 13 | EMAIL = '326333381@qq.com' 14 | AUTHOR = 'jianbing' 15 | VERSION = '0.0.7' 16 | REQUIRED = [ 17 | 'colorama' 18 | ] 19 | 20 | here = os.path.abspath(os.path.dirname(__file__)) 21 | 22 | with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f: 23 | long_description = '\n' + f.read() 24 | 25 | 26 | class UploadCommand(Command): 27 | """Support setup.py upload.""" 28 | 29 | description = 'Build and publish the package.' 30 | user_options = [] 31 | 32 | @staticmethod 33 | def status(s): 34 | """Prints things in bold.""" 35 | print('\033[1m{0}\033[0m'.format(s)) 36 | 37 | def initialize_options(self): 38 | pass 39 | 40 | def finalize_options(self): 41 | pass 42 | 43 | def run(self): 44 | try: 45 | self.status('Removing previous builds…') 46 | rmtree(os.path.join(here, 'dist')) 47 | except OSError: 48 | pass 49 | 50 | self.status('Building Source and Wheel (universal) distribution…') 51 | os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable)) 52 | 53 | self.status('Uploading the package to PyPi via Twine…') 54 | os.system('twine upload dist/*') 55 | 56 | sys.exit() 57 | 58 | 59 | setup( 60 | name=NAME, 61 | version=VERSION, 62 | description=DESCRIPTION, 63 | long_description=long_description, 64 | author=AUTHOR, 65 | author_email=EMAIL, 66 | url=URL, 67 | python_requires='>=3.6.0', 68 | packages=find_packages(), 69 | install_requires=REQUIRED, 70 | include_package_data=True, 71 | license='MIT', 72 | classifiers=[ 73 | 'License :: OSI Approved :: MIT License', 74 | 'Programming Language :: Python', 75 | 'Programming Language :: Python :: 3.6', 76 | 'Programming Language :: Python :: 3.7', 77 | 'Programming Language :: Python :: 3.8', 78 | 'Programming Language :: Python :: Implementation :: CPython', 79 | ], 80 | cmdclass={ 81 | 'upload': UploadCommand, 82 | }, 83 | ) 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # utx 2 | 3 | > 支持Python3.6及以上版本 4 | 5 | utx扩展了Python unittest框架的功能,起因是需要控制测试用例的执行顺序,而unittest的默认执行顺序是按照用例函数的名称进行排序,所以想要做一个可以无缝接入unittest的扩展功能库。 6 | 7 | ## 当前版本 8 | 9 | ```python 10 | V0.0.8 11 | ``` 12 | 13 | ## 安装 14 | 15 | ```python 16 | python setup.py install 17 | ``` 18 | 19 | ## 更新 20 | 21 | ```python 22 | pip uninstall utx # 需要先卸载旧的utx 23 | python setup.py install 24 | ``` 25 | 26 | 27 | 28 | ## 功能列表 29 | 30 | 31 | - 用例排序,只需要导入utx库,用例的执行顺序就会和编写顺序一致 32 | 33 | - 用例自定义标签,在 tag.py 里边添加标签,可以对测试用例指定多个标签。全部用例默认带有`ALL`标签。 34 | 35 | ```python 36 | @unique 37 | class Tag(Enum): 38 | ALL = NewTag("完整") # 完整测试标记,可以重命名,不要删除 39 | SMOKE = NewTag("冒烟") # 冒烟测试标记 40 | 41 | # 以下开始为扩展标签,自行调整 42 | V1_0_0 = NewTag("V1.0.0版本") 43 | V2_0_0 = NewTag("V2.0.0版本") 44 | ``` 45 | 46 | ```python 47 | class TestLegion(unittest.TestCase): 48 | 49 | @tag(Tag.SMOKE) 50 | def test_create_legion(self): 51 | pass 52 | 53 | @tag(Tag.V1_0_0, Tag.ALL) 54 | def test_quit_legion(self): 55 | """测试退出军团 56 | 57 | :return: 58 | """ 59 | print("测试退出军团") 60 | assert 1 == 2 61 | ``` 62 | 63 | - 运行指定标签的测试用例 64 | 65 | ```python 66 | from utx import * 67 | 68 | if __name__ == '__main__': 69 | setting.run_case = {Tag.ALL} # 运行全部测试用例 70 | # setting.run_case = {Tag.SMOKE} # 只运行SMOKE标记的测试用例 71 | # setting.run_case = {Tag.SMOKE, Tag.V1_0_0} # 只运行SMOKE和V1_0_0标记的测试用例 72 | 73 | runner = TestRunner() 74 | runner.add_case_dir(r"testcase") 75 | runner.run_test(report_title='接口自动化测试报告') 76 | ``` 77 | 78 | - 数据驱动 79 | ```python 80 | class TestLegion(unittest.TestCase): 81 | 82 | @data(["gold", 100], ["diamond", 500]) 83 | def test_bless(self, bless_type, cost): 84 | """测试公会祈福 85 | 86 | :param bless_type: 祈福类型 87 | :param cost: 消耗数量 88 | :return: 89 | """ 90 | print(bless_type) 91 | print(cost) 92 | 93 | @data(10001, 10002, 10003) 94 | def test_receive_bless_box(self, box_id): 95 | """ 测试领取祈福宝箱 96 | 97 | :return: 98 | """ 99 | print(box_id) 100 | 101 | # 默认会解包测试数据来一一对应函数参数,可以使用unpack=False,不进行解包 102 | 103 | class TestBattle(unittest.TestCase): 104 | @data({"gold": 1000, "diamond": 100}, {"gold": 2000, "diamond": 200}, unpack=False) 105 | def test_get_battle_reward(self, reward): 106 | """ 测试领取战斗奖励 107 | 108 | :return: 109 | """ 110 | print(reward) 111 | print("获得的钻石数量是:{}".format(reward['diamond'])) 112 | ``` 113 | 114 | - 检测用例是否编写了用例描述 115 | ```python 116 | 2017-11-13 12:00:19,334 WARNING legion.test_legion.test_bless没有用例描述 117 | ``` 118 | 119 | - 采集测试用例的print打印的信息到测试报告里边 120 | ```python 121 | @data({"gold": 1000, "diamond": 100}, {"gold": 2000, "diamond": 200}, unpack=False) 122 | def test_get_battle_reward(self, reward): 123 | """ 领取战斗奖励 124 | 125 | :return: 126 | """ 127 | print(reward) 128 | print("获得的钻石数量是:{}".format(reward['diamond'])) 129 | ``` 130 | 131 |  132 | 133 | 134 | - 执行测试时,显示测试进度 135 | ``` 136 | 2019-03-13 18:46:13,810 INFO 开始测试,用例数量总共15个,跳过5个,实际运行10个 137 | 2019-03-13 18:46:13,910 INFO start to test battle.test_tattle.test_start_battle (1/10) 138 | 2019-03-13 18:46:14,010 INFO start to test battle.test_tattle.test_skill_buff (2/10) 139 | 2019-03-13 18:46:14,111 INFO start to test battle.test_tattle.test_normal_attack (3/10) 140 | 2019-03-13 18:46:14,211 INFO start to test battle.test_tattle.test_get_battle_reward (4/10) 141 | 2019-03-13 18:46:14,211 DEBUG 测试领取战斗奖励,获得的钻石数量是:100 142 | 2019-03-13 18:46:14,311 INFO start to test battle.test_tattle.test_get_battle_reward (5/10) 143 | ``` 144 | 145 | - setting类提供多个设置选项进行配置 146 | ```python 147 | class setting: 148 | 149 | # 只运行的用例类型 150 | run_case = {Tag.SMOKE} 151 | 152 | # 开启用例排序 153 | sort_case = True 154 | 155 | # 每个用例的执行间隔,单位是秒 156 | execute_interval = 0.1 157 | 158 | # 开启检测用例描述 159 | check_case_doc = True 160 | 161 | # 显示完整用例名字(函数名字+参数信息) 162 | full_case_name = False 163 | 164 | # 测试报告显示的用例名字最大程度 165 | max_case_name_len = 80 166 | 167 | # 执行用例的时候,显示报错信息 168 | show_error_traceback = True 169 | 170 | # 测试报告样式1 171 | create_report_by_style_1 = True 172 | 173 | # 测试报告样式2 174 | create_report_by_style_2 = True 175 | 176 | # 在控制台显示print打印的内容 177 | show_print_in_console = False 178 | ``` 179 | 180 | 181 | - 集成两种测试报告样式,感谢两位作者的测试报告模版 182 | 183 | [测试报告1](https://github.com/findyou/HTMLTestRunnerCN) 184 | 185 |  186 | 187 | [测试报告2](https://github.com/zhangfei19841004/ztest) 188 | 189 |  190 | 191 | - 无缝接入unittest项目,导入utx包即可开始使用扩展功能,无需修改之前的代码 192 | 193 | 194 | ## 例子 195 | 196 | demo目录下,有几个例子: 197 | 198 | - ```run.py``` 一个完整使用utx功能的demo小项目 199 | 200 | - ```use_report.py``` 单独使用测试报告组件,不需要utx的其他扩展功能 201 | 202 | - ```debug_case.py``` 使用utx后,单独调试某个用例的例子 -------------------------------------------------------------------------------- /utx/runner.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | import time 4 | import os 5 | import io 6 | import datetime 7 | import sys 8 | import unittest 9 | from utx.core import Tool 10 | from . import log, setting 11 | 12 | result_data = dict() 13 | result_data['testResult'] = [] 14 | current_class_name = "" 15 | STATUS = { 16 | 0: 'Pass', 17 | 1: 'Fail', 18 | 2: 'Error', 19 | 3: 'Skip', 20 | } 21 | 22 | 23 | class _TestResult(unittest.TestResult): 24 | def __init__(self, verbosity=1): 25 | super().__init__(verbosity) 26 | self.outputBuffer = io.StringIO() 27 | self.raw_stdout = None 28 | self.raw_stderr = None 29 | self.success_count = 0 30 | self.failure_count = 0 31 | self.skip_count = 0 32 | self.error_count = 0 33 | self.verbosity = verbosity 34 | self.result = [] 35 | self._case_start_time = 0 36 | self._case_run_time = 0 37 | 38 | def startTest(self, test): 39 | self._case_start_time = time.time() 40 | super().startTest(test) 41 | self.raw_stdout = sys.stdout 42 | self.raw_stderr = sys.stderr 43 | sys.stdout = self.outputBuffer 44 | sys.stderr = self.outputBuffer 45 | 46 | def complete_output(self): 47 | self._case_run_time = time.time() - self._case_start_time 48 | if self.raw_stdout: 49 | sys.stdout = self.raw_stdout 50 | sys.stderr = self.raw_stderr 51 | 52 | result = self.outputBuffer.getvalue() 53 | self.outputBuffer.seek(0) 54 | self.outputBuffer.truncate() 55 | if result and setting.show_print_in_console: 56 | log._print(result.strip()) 57 | return result 58 | 59 | def stopTest(self, test): 60 | self.complete_output() 61 | 62 | def addSuccess(self, test): 63 | self.success_count += 1 64 | super().addSuccess(test) 65 | output = self.complete_output() 66 | self.result.append((0, test, output, '', self._case_run_time)) 67 | 68 | def addError(self, test, err): 69 | self.error_count += 1 70 | super().addError(test, err) 71 | _, _exc_str = self.errors[-1] 72 | output = self.complete_output() 73 | self.result.append((2, test, output, _exc_str, self._case_run_time)) 74 | log.error('TestCase Error') 75 | if setting.show_error_traceback: 76 | log.error(_exc_str) 77 | 78 | def addSkip(self, test, reason): 79 | self.skip_count += 1 80 | super().addSkip(test, reason) 81 | self.result.append((3, test, "", "", 0.0)) 82 | 83 | def addFailure(self, test, err): 84 | self.failure_count += 1 85 | super().addFailure(test, err) 86 | _, _exc_str = self.failures[-1] 87 | output = self.complete_output() 88 | self.result.append((1, test, output, _exc_str, self._case_run_time)) 89 | log.error('TestCase Failed') 90 | if setting.show_error_traceback: 91 | log.error(_exc_str) 92 | 93 | 94 | class _TestRunner: 95 | def __init__(self, report_title, report_dir, verbosity=1, description=""): 96 | self.report_dir = report_dir 97 | self.verbosity = verbosity 98 | self.title = report_title 99 | self.description = description 100 | self.start_time = datetime.datetime.now() 101 | self.stop_time = None 102 | 103 | def run(self, test): 104 | msg = "开始测试,用例数量总共{}个,跳过{}个,实际运行{}个" 105 | log.info(msg.format(Tool.total_case_num, 106 | Tool.total_case_num - Tool.actual_case_num, 107 | Tool.actual_case_num)) 108 | result = _TestResult(self.verbosity) 109 | test(result) 110 | self.stop_time = datetime.datetime.now() 111 | self.analyze_test_result(result) 112 | log.info('Time Elapsed: {}'.format(self.stop_time - self.start_time)) 113 | 114 | from utx.report import style_1, style_2 115 | if setting.create_report_by_style_1: 116 | file_path = os.path.join(self.report_dir, 117 | r"{}-style-1.html".format(self.start_time.strftime("%Y-%m-%d-%H-%M-%S"))) 118 | style_1.build_report(file_path, result_data) 119 | 120 | if setting.create_report_by_style_2: 121 | file_path = os.path.join(self.report_dir, 122 | r"{}-style-2.html".format(self.start_time.strftime("%Y-%m-%d-%H-%M-%S"))) 123 | style_2.build_report(file_path, result_data) 124 | 125 | @staticmethod 126 | def sort_result(case_results): 127 | rmap = {} 128 | classes = [] 129 | for n, t, o, e, run_time in case_results: 130 | cls = t.__class__ 131 | if cls not in rmap: 132 | rmap[cls] = [] 133 | classes.append(cls) 134 | rmap[cls].append((n, t, o, e, run_time)) 135 | r = [(cls, rmap[cls]) for cls in classes] 136 | return r 137 | 138 | def analyze_test_result(self, result): 139 | result_data["reportName"] = self.title 140 | result_data["beginTime"] = str(self.start_time)[:19] 141 | result_data["totalTime"] = str(self.stop_time - self.start_time) 142 | 143 | sorted_result = self.sort_result(result.result) 144 | for cid, (cls, cls_results) in enumerate(sorted_result): 145 | pass_num = fail_num = error_num = skip_num = 0 146 | for case_state, *_ in cls_results: 147 | if case_state == 0: 148 | pass_num += 1 149 | elif case_state == 1: 150 | fail_num += 1 151 | elif case_state == 2: 152 | error_num += 1 153 | else: 154 | skip_num += 1 155 | 156 | name = "{}.{}".format(cls.__module__, cls.__name__) 157 | global current_class_name 158 | current_class_name = name 159 | 160 | for tid, (state_id, t, o, e, run_time) in enumerate(cls_results): 161 | 162 | name = t.id().split('.')[-1] 163 | doc = t.shortDescription() or "" 164 | case_data = dict() 165 | case_data['className'] = current_class_name 166 | case_data['methodName'] = name 167 | case_data['spendTime'] = "{:.2}S".format(run_time) 168 | case_data['description'] = doc 169 | case_data['log'] = o + e 170 | if STATUS[state_id] == "Pass": 171 | case_data['status'] = "成功" 172 | if STATUS[state_id] == "Fail": 173 | case_data['status'] = "失败" 174 | if STATUS[state_id] == "Error": 175 | case_data['status'] = "错误" 176 | if STATUS[state_id] == "Skip": 177 | case_data['status'] = "跳过" 178 | result_data['testResult'].append(case_data) 179 | 180 | result_data["testPass"] = result.success_count 181 | result_data["testAll"] = result.success_count + result.failure_count + result.error_count + result.skip_count 182 | result_data["testFail"] = result.failure_count 183 | result_data["testSkip"] = result.skip_count 184 | result_data["testError"] = result.error_count 185 | 186 | 187 | class TestRunner: 188 | 189 | def __init__(self): 190 | self.case_dirs = [] 191 | 192 | def add_case_dir(self, dir_path): 193 | """添加测试用例文件夹,多次调用可以添加多个文件夹,会按照文件夹的添加顺序执行用例 194 | 195 | runner = TestRunner() 196 | runner.add_case_dir(r"testcase\chat") 197 | runner.add_case_dir(r"testcase\battle") 198 | runner.run_test(report_title='接口自动化测试报告') 199 | 200 | :param dir_path: 201 | :return: 202 | """ 203 | if not os.path.exists(dir_path): 204 | raise Exception("测试用例文件夹不存在:{}".format(dir_path)) 205 | if dir_path in self.case_dirs: 206 | log.warn("测试用例文件夹已经存在了:{}".format(dir_path)) 207 | else: 208 | self.case_dirs.append(dir_path) 209 | 210 | def run_test(self, report_title='接口自动化测试报告'): 211 | 212 | if not self.case_dirs: 213 | raise Exception("请先调用add_case_dir方法,添加测试用例文件夹") 214 | 215 | if not os.path.exists("report"): 216 | os.mkdir("report") 217 | 218 | report_dir = os.path.abspath("report") 219 | suite = unittest.TestSuite() 220 | for case_path in self.case_dirs: 221 | suite.addTests(unittest.TestLoader().discover(case_path)) 222 | _TestRunner(report_dir=report_dir, report_title=report_title).run(suite) 223 | 224 | print("测试完成,请查看报告") 225 | os.system("start report") 226 | -------------------------------------------------------------------------------- /utx/core.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | import re 4 | import functools 5 | import time 6 | import unittest 7 | from .setting import setting 8 | from . import log 9 | from .tag import Tag 10 | 11 | CASE_TAG_FLAG = "__case_tag__" 12 | CASE_DATA_FLAG = "__case_data__" 13 | CASE_DATA_UNPACK_FLAG = "__case_data_unpack__" 14 | CASE_ID_FLAG = "__case_id__" 15 | CASE_INFO_FLAG = "__case_info__" 16 | CASE_RUN_INDEX_FlAG = "__case_run_index_flag__" 17 | CASE_SKIP_FLAG = "__unittest_skip__" 18 | CASE_SKIP_REASON_FLAG = "__unittest_skip_why__" 19 | 20 | __all__ = ["skip", "skip_if", "data", "tag", "stop_patch", "run_case"] 21 | 22 | 23 | def skip(reason): 24 | def wrap(func): 25 | return unittest.skip(reason)(func) 26 | 27 | return wrap 28 | 29 | 30 | def skip_if(condition, reason): 31 | def wrap(func): 32 | return unittest.skipIf(condition, reason)(func) 33 | 34 | return wrap 35 | 36 | 37 | def data(*values, unpack=True): 38 | """注入测试数据,可以做为测试用例的数据驱动 39 | 1. 单一参数的测试用例 40 | @data(10001, 10002, 10003) 41 | def test_receive_bless_box(self, box_id): 42 | print(box_id) 43 | 44 | 2. 多个参数的测试用例 45 | @data(["gold", 100], ["diamond", 500]) 46 | def test_bless(self, bless_type, award): 47 | print(bless_type) 48 | print(award) 49 | 50 | 3. 是否对测试数据进行解包 51 | @data({"gold": 1000, "diamond": 100}, {"gold": 2000, "diamond": 200}, unpack=False) 52 | def test_get_battle_reward(self, reward): 53 | print(reward) 54 | print("获得的钻石数量是:{}".format(reward['diamond'])) 55 | 56 | :param values:测试数据 57 | :param unpack: 是否解包 58 | :return: 59 | """ 60 | 61 | def wrap(func): 62 | if hasattr(func, CASE_DATA_FLAG): 63 | log.error("{}的测试数据只能初始化一次".format(func.__name__)) 64 | else: 65 | setattr(func, CASE_DATA_FLAG, values) 66 | setattr(func, CASE_DATA_UNPACK_FLAG, unpack) 67 | return func 68 | 69 | return wrap 70 | 71 | 72 | def tag(*tag_type): 73 | """指定测试用例的标签,可以作为测试用例分组使用,用例默认会有Tag.ALL标签,支持同时设定多个标签,如: 74 | @tag(Tag.V1_0_0, Tag.SMOKE) 75 | def test_func(self): 76 | pass 77 | 78 | :param tag_type:标签类型,在tag.py里边自定义 79 | :return: 80 | """ 81 | 82 | def wrap(func): 83 | if not hasattr(func, CASE_TAG_FLAG): 84 | tags = {Tag.ALL} 85 | tags.update(tag_type) 86 | setattr(func, CASE_TAG_FLAG, tags) 87 | else: 88 | getattr(func, CASE_TAG_FLAG).update(tag_type) 89 | return func 90 | 91 | return wrap 92 | 93 | 94 | def _handler(func): 95 | @functools.wraps(func) 96 | def wrap(*args, **kwargs): 97 | time.sleep(setting.execute_interval) 98 | msg = "start to test {} ({}/{})".format(getattr(func, CASE_INFO_FLAG), 99 | getattr(func, CASE_RUN_INDEX_FlAG), 100 | Tool.actual_case_num) 101 | log.info(msg) 102 | result = func(*args, **kwargs) 103 | return result 104 | 105 | return wrap 106 | 107 | 108 | class Tool: 109 | actual_case_num = 0 110 | total_case_num = 0 111 | 112 | @classmethod 113 | def create_case_id(cls): 114 | cls.total_case_num += 1 115 | return cls.total_case_num 116 | 117 | @classmethod 118 | def create_actual_run_index(cls): 119 | cls.actual_case_num += 1 120 | return cls.actual_case_num 121 | 122 | @staticmethod 123 | def modify_func_name(func): 124 | """修改函数名字,实现排序 eg test_fight ---> test_00001_fight 125 | 126 | :param func: 127 | :return: 128 | """ 129 | case_id = Tool.create_case_id() 130 | setattr(func, CASE_ID_FLAG, case_id) 131 | if setting.sort_case: 132 | func_name = func.__name__.replace("test_", "test_{:05d}_".format(case_id)) 133 | else: 134 | func_name = func.__name__ 135 | return func_name 136 | 137 | @staticmethod 138 | def general_case_name_with_test_data(func_name, index, test_data): 139 | if setting.full_case_name: 140 | params_str = "_".join([str(_) for _ in test_data]).replace(".", "") 141 | func_name += "_{:05d}_{}".format(index, params_str) 142 | else: 143 | func_name += "_{:05d}".format(index) 144 | if len(func_name) > setting.max_case_name_len: 145 | func_name = func_name[:setting.max_case_name_len] + "……" 146 | return func_name 147 | 148 | @staticmethod 149 | def create_case_with_case_data(func): 150 | result = dict() 151 | for index, test_data in enumerate(getattr(func, CASE_DATA_FLAG), 1): 152 | if not hasattr(func, CASE_SKIP_FLAG): 153 | setattr(func, CASE_RUN_INDEX_FlAG, Tool.create_actual_run_index()) 154 | 155 | func_name = Tool.modify_func_name(func) 156 | if isinstance(test_data, list): 157 | func_name = Tool.general_case_name_with_test_data(func_name, index, test_data) 158 | if getattr(func, CASE_DATA_UNPACK_FLAG, None): 159 | result[func_name] = _handler(_feed_data(*test_data)(func)) 160 | else: 161 | result[func_name] = _handler(_feed_data(test_data)(func)) 162 | 163 | elif isinstance(test_data, dict): 164 | func_name = Tool.general_case_name_with_test_data(func_name, index, test_data.values()) 165 | if getattr(func, CASE_DATA_UNPACK_FLAG, None): 166 | result[func_name] = _handler(_feed_data(**test_data)(func)) 167 | else: 168 | result[func_name] = _handler(_feed_data(test_data)(func)) 169 | 170 | elif isinstance(test_data, (int, str, bool, float)): 171 | func_name = Tool.general_case_name_with_test_data(func_name, index, [test_data]) 172 | result[func_name] = _handler(_feed_data(test_data)(func)) 173 | 174 | else: 175 | raise Exception("无法解析{}".format(test_data)) 176 | 177 | return result 178 | 179 | @staticmethod 180 | def create_case_without_case_data(func): 181 | if not hasattr(func, CASE_SKIP_FLAG): 182 | setattr(func, CASE_RUN_INDEX_FlAG, Tool.create_actual_run_index()) 183 | 184 | result = dict() 185 | func_name = Tool.modify_func_name(func) 186 | if len(func_name) > setting.max_case_name_len: 187 | func_name = func_name[:setting.max_case_name_len] + "……" 188 | result[func_name] = _handler(func) 189 | return result 190 | 191 | @staticmethod 192 | def filter_test_case(funcs_dict): 193 | funcs = dict() 194 | cases = dict() 195 | for i in funcs_dict: 196 | if i.startswith("test_"): 197 | cases[i] = funcs_dict[i] 198 | else: 199 | funcs[i] = funcs_dict[i] 200 | 201 | return funcs, cases 202 | 203 | 204 | def _feed_data(*args, **kwargs): 205 | def wrap(func): 206 | @functools.wraps(func) 207 | def _wrap(self): 208 | return func(self, *args, **kwargs) 209 | 210 | return _wrap 211 | 212 | return wrap 213 | 214 | 215 | class Meta(type): 216 | def __new__(cls, clsname, bases, attrs): 217 | funcs, cases = Tool.filter_test_case(attrs) 218 | for test_case in cases.values(): 219 | if not hasattr(test_case, CASE_TAG_FLAG): 220 | setattr(test_case, CASE_TAG_FLAG, {Tag.ALL}) # 没有指定tag的用例,默认带有tag:ALL 221 | 222 | # 注入用例信息 223 | case_info = "{}.{}".format(test_case.__module__, test_case.__name__) 224 | setattr(test_case, CASE_INFO_FLAG, case_info) 225 | 226 | # 检查用例描述 227 | if setting.check_case_doc and not test_case.__doc__: 228 | log.warn("{}没有用例描述".format(case_info)) 229 | 230 | # 过滤不执行的用例 231 | if not getattr(test_case, CASE_TAG_FLAG) & set(setting.run_case): 232 | continue 233 | 234 | # 注入测试数据 235 | if hasattr(test_case, CASE_DATA_FLAG): 236 | funcs.update(Tool.create_case_with_case_data(test_case)) 237 | else: 238 | funcs.update(Tool.create_case_without_case_data(test_case)) 239 | 240 | return super(Meta, cls).__new__(cls, clsname, bases, funcs) 241 | 242 | 243 | class _TestCase(unittest.TestCase, metaclass=Meta): 244 | def shortDescription(self): 245 | """覆盖父类的方法,获取函数的注释 246 | 247 | :return: 248 | """ 249 | doc = self._testMethodDoc 250 | doc = doc and doc.split()[0].strip() or None 251 | return doc 252 | 253 | 254 | TestCaseBackup = unittest.TestCase 255 | unittest.TestCase = _TestCase 256 | 257 | 258 | def stop_patch(): 259 | unittest.TestCase = TestCaseBackup 260 | 261 | 262 | def run_case(case_class, case_name: str): 263 | setting.execute_interval = 0.3 264 | r = re.compile(case_name.replace("test_", "test(_\d+)?_")) 265 | suite = unittest.TestSuite() 266 | for i in unittest.TestLoader().loadTestsFromTestCase(case_class): 267 | if r.match(getattr(i, "_testMethodName")): 268 | suite.addTest(i) 269 | unittest.TextTestRunner(verbosity=0).run(suite) 270 | -------------------------------------------------------------------------------- /utx/report/style_1.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | 4 | html_head = r""" 5 | 6 | 7 | 8 |
9 |开始时间 : {begin_time}
175 |合计耗时 : {total_time}
176 |测试结果 : 共 {test_all},通过 {test_pass},失败 {test_fail},错误 {test_error},跳过 {test_skip},通过率= {test_pass_per}
177 | 178 | 179 |183 | 概要{{ {test_pass_per} }} 184 | 通过{{ {test_pass} }} 185 | 失败{{ {test_fail} }} 186 | 错误{{ {test_error} }} 187 | 所有{{ {test_all} }} 188 |
189 || 用例集/测试用例 | 201 |总计 | 202 |通过 | 203 |失败 | 204 |错误 | 205 |跳过 | 206 |详细 | 207 |
| 总计 | 214 |{test_all} | 215 |{test_pass} | 216 |{test_fail} | 217 |{test_error} | 218 |{test_skip} | 219 |通过率:{test_pass_per} | 220 |
{case_log}
277 | {case_log}
296 | {case_log}
313 | 开始时间 : 2019-03-13 18:46:13
170 |合计耗时 : 0:00:01.003057
171 |测试结果 : 共 15,通过 8,失败 1,错误 1,跳过 5,通过率= 53.33%
172 | 173 | 174 |178 | 概要{ 53.33% } 179 | 通过{ 8 } 180 | 失败{ 1 } 181 | 错误{ 1 } 182 | 所有{ 15 } 183 |
184 || 用例集/测试用例 | 196 |总计 | 197 |通过 | 198 |失败 | 199 |错误 | 200 |跳过 | 201 |详细 | 202 |
| battle.test_tattle.TestBattle | 208 |5 | 209 |5 | 210 |0 | 211 |0 | 212 |0 | 213 |详细 | 214 |
|
218 | test_00001_start_battle(测试开始战斗)
219 | |
220 |
221 |
222 |
223 |
224 |
227 | 测试开始战斗 225 |226 | |
228 | |||||
|
232 | test_00002_skill_buff(测试技能buff)
233 | |
234 |
235 |
236 |
237 |
238 |
241 | 测试技能buff 239 |240 | |
242 | |||||
|
246 | test_00003_normal_attack(测试普通攻击)
247 | |
248 |
249 |
250 |
251 |
252 |
255 | 测试普通攻击 253 |254 | |
256 | |||||
|
260 | test_00004_get_battle_reward_00001_1000_100(测试领取战斗奖励)
261 | |
262 |
263 |
264 |
265 |
266 |
270 | {'gold': 1000, 'diamond': 100}
267 | 测试领取战斗奖励,获得的钻石数量是:100
268 |
269 | |
271 | |||||
|
275 | test_00005_get_battle_reward_00002_2000_200(测试领取战斗奖励)
276 | |
277 |
278 |
279 |
280 |
281 |
285 | {'gold': 2000, 'diamond': 200}
282 | 测试领取战斗奖励,获得的钻石数量是:200
283 |
284 | |
286 | |||||
| chat.test_chat.TestChat | 290 |3 | 291 |0 | 292 |0 | 293 |1 | 294 |2 | 295 |详细 | 296 |
test_00006_chat_in_world_channel(测试世界聊天) |
300 |
301 |
304 |
305 |
306 |
307 |
308 |
317 | 测试世界聊天
309 | Traceback (most recent call last):
310 | File "D:\github\utx\utx\core.py", line 101, in wrap
311 | result = func(*args, **kwargs)
312 | File "D:\github\utx\demo\testcase\chat\test_chat.py", line 15, in test_chat_in_world_channel
313 | raise Exception("运行报错了")
314 | Exception: 运行报错了
315 |
316 | |
318 | |||||
|
322 | test_00007_chat_in_personal_channel(测试私聊)
323 | |
324 | 325 | 跳过 326 | | 327 ||||||
|
331 | test_00008_chat_in_union_channel(测试公会聊天)
332 | |
333 | 334 | 跳过 335 | | 336 ||||||
| legion.test_legion.TestLegion | 340 |7 | 341 |3 | 342 |1 | 343 |0 | 344 |3 | 345 |详细 | 346 |
|
350 | test_00009_create_legion(测试创建军团)
351 | |
352 |
353 |
354 |
355 |
356 |
360 | 运行setUp方法 357 | 运行tearDown方法 358 |359 | |
361 | |||||
|
365 | test_00010_bless_00001_gold_100(测试公会祈福)
366 | |
367 |
368 |
369 |
370 |
371 |
377 | 运行setUp方法 372 | gold 373 | 100 374 | 运行tearDown方法 375 |376 | |
378 | |||||
|
382 | test_00011_bless_00002_diamond_500(测试公会祈福)
383 | |
384 |
385 |
386 |
387 |
388 |
394 | 运行setUp方法 389 | diamond 390 | 500 391 | 运行tearDown方法 392 |393 | |
395 | |||||
|
399 | test_00012_receive_bless_box_00001_10001(测试领取祈福宝箱)
400 | |
401 | 402 | 跳过 403 | | 404 ||||||
|
408 | test_00013_receive_bless_box_00002_10002(测试领取祈福宝箱)
409 | |
410 | 411 | 跳过 412 | | 413 ||||||
|
417 | test_00014_receive_bless_box_00003_10003(测试领取祈福宝箱)
418 | |
419 | 420 | 跳过 421 | | 422 ||||||
|
426 | test_00015_quit_legion(测试退出军团)
427 | |
428 |
429 |
432 |
433 |
434 |
435 |
436 |
447 | 运行setUp方法 437 | 测试退出军团 438 | 运行tearDown方法 439 | Traceback (most recent call last): 440 | File "D:\github\utx\utx\core.py", line 101, in wrap 441 | result = func(*args, **kwargs) 442 | File "D:\github\utx\demo\testcase\legion\test_legion.py", line 50, in test_quit_legion 443 | assert 1 == 2 444 | AssertionError 445 |446 | |
448 | |||||
| 总计 | 453 |15 | 454 |8 | 455 |1 | 456 |1 | 457 |5 | 458 |通过率:53.33% | 459 |