├── .gitignore ├── README.md ├── base ├── __init__.py ├── action.py ├── conftest_android.py ├── conftest_ios.py ├── environment.py ├── page.py ├── run.py ├── shell.py ├── utils.py └── verify.py ├── data ├── apk │ └── jumei.apk ├── args_data.yaml ├── config.yaml └── config_android.yaml ├── debug.py ├── env_check.py ├── lib ├── pages │ ├── buypage.py │ ├── productpage.py │ ├── set.py │ ├── userpage.py │ └── vedio.py └── reuse_business │ ├── base_business.py │ └── shopping_business.py ├── report ├── html │ ├── app.js │ ├── data │ │ ├── attachments │ │ │ ├── 184e4b9f713ed749.txt │ │ │ ├── 1b054209eb500c1e.txt │ │ │ ├── 2009125f090a36cc.txt │ │ │ ├── 21c2d6d39434b83c.txt │ │ │ ├── 32919f953a11695e.txt │ │ │ ├── 364443a71485466e.png │ │ │ ├── 36d231cb37c04a17.txt │ │ │ ├── 39bdf573c49e6278.txt │ │ │ ├── 3b5d712ca2cfa385.txt │ │ │ ├── 3de4c5abcaa50cb.txt │ │ │ ├── 4415a145575fd6d8.png │ │ │ ├── 5337e0bfb50b06c0.png │ │ │ ├── 587194d88e90bdd5.txt │ │ │ ├── 6404365aaa5f191a.png │ │ │ ├── 650bb9c791a42f2e.txt │ │ │ ├── 69de7f3952a72a0d.png │ │ │ ├── 6c7820d70b256863.txt │ │ │ ├── 6d704f1e86ebd4df.txt │ │ │ ├── 71e3657056b93481.txt │ │ │ ├── 79434b6d979f4894.txt │ │ │ ├── 79eb5a8782924b4e.txt │ │ │ ├── 7e6ae649c1b6df2a.txt │ │ │ ├── 822a05989c58a85b.txt │ │ │ ├── 9e3c4826300de3ad.txt │ │ │ ├── a007d84425b5bb63.png │ │ │ ├── a2fef45cfac7b88.png │ │ │ ├── ab8981d949a2bb34.txt │ │ │ ├── ab94871d11b3a4c2.txt │ │ │ ├── aba9b39786212361.png │ │ │ ├── b449cc3f836fe944.txt │ │ │ ├── b90519268f26a77e.txt │ │ │ ├── bb68d42c3a6abca2.txt │ │ │ ├── bc1be12f7bde1a6.png │ │ │ ├── bed1b75cd7491c29.txt │ │ │ ├── c28d08ff32e6537.txt │ │ │ ├── c354537fab992c28.txt │ │ │ ├── c6d30d954b758685.png │ │ │ ├── d292a7adda173007.txt │ │ │ ├── de9a4d61f65ac32b.txt │ │ │ ├── e0c69be8f1448ca3.txt │ │ │ ├── e3cb25556374b8fc.txt │ │ │ ├── e3ce77b42d6a67bc.txt │ │ │ └── ffff07e22303b196.txt │ │ ├── behaviors.csv │ │ ├── behaviors.json │ │ ├── categories.csv │ │ ├── categories.json │ │ ├── packages.json │ │ ├── suites.csv │ │ ├── suites.json │ │ ├── test-cases │ │ │ ├── 1c34a555846b7834.json │ │ │ ├── 24f58f1ec11332d9.json │ │ │ ├── 2badf96700036808.json │ │ │ ├── 368f23af01311881.json │ │ │ ├── 5c92766a12bb5ee2.json │ │ │ ├── 5e5ab8d7f354b64e.json │ │ │ ├── 86e14bf2f8865824.json │ │ │ ├── b21acd4f81e0178b.json │ │ │ ├── cc5b3686faaafc7d.json │ │ │ ├── ec79099cdc5058fa.json │ │ │ └── f0ae3bd5a8ce2bb.json │ │ └── timeline.json │ ├── export │ │ ├── influxDbData.txt │ │ ├── mail.html │ │ └── prometheusData.txt │ ├── favicon.ico │ ├── history │ │ ├── categories-trend.json │ │ ├── duration-trend.json │ │ ├── history-trend.json │ │ ├── history.json │ │ └── retry-trend.json │ ├── index.html │ ├── plugins │ │ ├── behaviors │ │ │ └── index.js │ │ ├── packages │ │ │ └── index.js │ │ └── screen-diff │ │ │ ├── index.js │ │ │ └── styles.css │ ├── styles.css │ └── widgets │ │ ├── behaviors.json │ │ ├── categories-trend.json │ │ ├── categories.json │ │ ├── duration-trend.json │ │ ├── duration.json │ │ ├── environment.json │ │ ├── executors.json │ │ ├── history-trend.json │ │ ├── launch.json │ │ ├── retry-trend.json │ │ ├── severity.json │ │ ├── status-chart.json │ │ ├── suites.json │ │ └── summary.json └── xml │ ├── 0ac8a7b4-ca14-4f30-8048-929374fc143d-attachment.txt │ ├── 0b80182a-5c2d-44fd-926e-b8970e982495-attachment.txt │ ├── 0d40c3e0-f16c-4f30-9208-348a2d7134ae-attachment.png │ ├── 0f133a6f-8510-4798-98f3-2c49a8034ad3-container.json │ ├── 135030ec-ef31-4ac4-8d16-25db85813b8f-attachment.txt │ ├── 16486324-2ffb-443c-bc74-df4be503793e-result.json │ ├── 1bc24c7e-c484-46e9-95a5-66f76da9c067-container.json │ ├── 1dea38e3-f7b0-4dc0-a433-f87c88c831cf-container.json │ ├── 1e68c468-f52e-42e1-8de8-087700dbe79d-container.json │ ├── 1f3702af-add8-40d9-a98a-bb55ca41e533-attachment.png │ ├── 21abedd4-d6b7-4210-b440-b78ea3791748-container.json │ ├── 23e0a33d-755d-495a-a7d3-662b31b63b3c-attachment.txt │ ├── 26cdddf9-e4d3-4591-940d-ec91e044d7ab-attachment.txt │ ├── 28a2f24c-7f80-42fd-bd43-513f93f183cd-container.json │ ├── 2ae9ebdc-c8fc-4c99-b3a2-95e7cbf8e00a-attachment.txt │ ├── 2fd16e0b-5cb0-458a-8e7d-c4c3104efea1-attachment.txt │ ├── 30b95c23-126c-4ae8-a142-d5cb1b640503-attachment.txt │ ├── 3169bc89-e5e3-409c-8f4c-e0900691703e-attachment.txt │ ├── 32275fd0-7b26-458a-a314-d7f18c08c6bd-attachment.txt │ ├── 33712355-4cc3-45b2-aaf5-f94b0777b972-container.json │ ├── 3502b925-0d38-4e4f-b528-038c9bc3cd66-attachment.txt │ ├── 3ad22042-0c49-4c4e-b81a-dd4bd5ce6787-container.json │ ├── 3ae6801d-bf4c-4c75-bde4-d39f7e033b65-attachment.txt │ ├── 4ac4ca22-d3f2-490b-96a3-e46dec73bdd9-attachment.txt │ ├── 4b7ee5b5-f617-42c0-8155-a94b7d35185b-container.json │ ├── 4c65ef77-5e6d-40e3-abbc-293b84cb4789-container.json │ ├── 53891f13-2a0f-4734-8346-9ecfdec58401-attachment.txt │ ├── 543b24cf-ea3b-4ecf-b1ba-f5e4eaebf854-attachment.txt │ ├── 546e3c42-6610-42b9-a6a3-06872878ce73-attachment.png │ ├── 55c612c9-8a4b-4723-b3b5-a914d236080e-container.json │ ├── 594817c9-9d9b-4b67-be5a-239b5f5d30e4-attachment.txt │ ├── 5af2875d-ab16-472c-9b24-d38ebe68eaf6-container.json │ ├── 5ca2bb07-6737-4e95-9568-20b93df13c26-attachment.txt │ ├── 5d57814e-f7f3-4c4c-b78a-ce7b9fe3d9d7-attachment.png │ ├── 5e362689-1c59-4a25-b9ec-dda395fb8754-result.json │ ├── 603aa3ba-f091-4d66-af51-ec1e5e48a621-attachment.txt │ ├── 60476879-f3f9-4989-b775-4fd9fb8a50fa-attachment.txt │ ├── 62e86b44-98ef-4aca-bbba-48f145555a82-container.json │ ├── 692fbc9d-702d-4d9b-9a59-bb7e00f89f4b-result.json │ ├── 6e55e899-68c5-4894-9af2-1ed5e00242fe-result.json │ ├── 6fce2fca-f78d-4b6f-86e4-61486ae7a5da-attachment.txt │ ├── 768689ab-c326-42c8-9f8a-dadf37c12f1d-attachment.png │ ├── 838e8e5d-a86c-44d3-8052-f3cf5c33015d-result.json │ ├── 86139c2a-aea2-47d8-b30a-5eef2e73f365-attachment.txt │ ├── 8ada9ae0-65b8-43d7-88f9-68d5851714b3-attachment.txt │ ├── 8d106794-b06d-45ef-a568-c85e52e0b9ba-container.json │ ├── 915741d4-fe12-4e39-aa4a-574089abd8cd-container.json │ ├── 968c72e1-375b-4648-9190-a7133f0ffd6b-attachment.png │ ├── 9dfd1b3b-8101-4f15-8c5b-4dcad7ea0021-container.json │ ├── 9f048740-a1ce-4fb2-97c1-ae5f9a198688-container.json │ ├── a2051384-2c1b-4333-acf7-82caaabfb634-attachment.txt │ ├── a224c455-7342-41b7-8bd3-d9ba8a137764-attachment.txt │ ├── a567b8aa-bfab-4890-a82f-02e2d99cefcb-container.json │ ├── a88b0ddc-fcd4-46ab-a869-913ef616ca03-attachment.txt │ ├── acb7cda0-b685-4444-9f5e-4d6035c665bc-container.json │ ├── b67ce731-621d-4b68-ac43-4c9487b043cb-attachment.png │ ├── b9329203-7a34-47ed-8e83-c0ca0d5fe236-result.json │ ├── bc21fc83-a9c9-4c05-8cd8-523b9d63276e-attachment.txt │ ├── be0b3314-b044-4202-a652-1ca30442a1d7-container.json │ ├── c4da1d1b-fcdf-425c-a4f1-ab0589851e6d-result.json │ ├── c8e6ad99-cf28-4e05-a155-fd41b3aa3970-attachment.txt │ ├── cb2f0c04-b71a-4e1b-bc30-1f6d5ea55554-container.json │ ├── cd40a3d8-7d79-46eb-a773-f8d8ce6c3cea-result.json │ ├── cee3e787-7ac9-431e-be59-7a3649a01f9b-container.json │ ├── cf4e24b4-07eb-47d6-9eed-48f3f76db6f7-attachment.png │ ├── d16749bf-9001-464c-b099-3ad7d11ab059-attachment.png │ ├── d250f3a8-fd22-49dd-a10f-97aaad63a8dc-attachment.txt │ ├── d2f040e2-5930-4b7b-a29c-fd91ee2aa005-container.json │ ├── d7af59e8-f39b-43d4-b868-696892792deb-attachment.txt │ ├── d843718e-d2d1-4fb8-a491-c8d73570195f-attachment.txt │ ├── da029da3-6ab3-4591-b2f2-ea2efbfb1cdf-attachment.txt │ ├── da44832c-0a1a-4e54-aab3-88269f1306ff-attachment.txt │ ├── e1692a5e-2dab-4591-977a-87ae6dfd595b-container.json │ ├── e20bb103-bd3a-4fc4-b0e5-b3a26482839c-result.json │ ├── e6773643-77f7-4893-8324-8de181c0ef6c-result.json │ ├── e86819b3-9efe-4f9b-a8b3-5d4e53b10ddf-attachment.png │ ├── e9d5fee0-9a43-43d3-8f3c-2eaa8e473f48-container.json │ ├── efe03640-0e8a-4bbb-8193-5e001ebcdd79-container.json │ ├── environment.properties │ ├── f096293f-0f79-49bc-a93d-6788cd87963e-attachment.txt │ ├── f16bad53-ac59-4ac7-b2a4-731d3329d142-container.json │ ├── f662782f-5a06-42dd-868f-3d0967c0be4a-container.json │ └── fc6cff4e-2457-45a5-99e7-3437d611660b-result.json ├── requirements.txt ├── run.py └── tests ├── test_suit2 ├── __init__.py ├── conftest.py └── test_demo2.py ├── test_usercenter ├── __init__.py ├── conftest.py └── test_returngoods.py └── test_vedio ├── __init__.py ├── conftest.py └── test_videorelease.py /.gitignore: -------------------------------------------------------------------------------- 1 | giled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | wheels/ 22 | share/python-wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .nox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | .pytest_cache/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | local_settings.py 58 | db.sqlite3 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/_build/ 69 | 70 | # PyBuilder 71 | target/ 72 | 73 | # Jupyter Notebook 74 | .ipynb_checkpoints 75 | 76 | # IPython 77 | profile_default/ 78 | ipython_config.py 79 | 80 | # pyenv 81 | .python-version 82 | 83 | # celery beat schedule file 84 | celerybeat-schedule 85 | 86 | # SageMath parsed files 87 | *.sage.py 88 | 89 | # Environments 90 | .env 91 | .venv 92 | env/ 93 | venv/ 94 | ENV/ 95 | env.bak/ 96 | venv.bak/ 97 | 98 | # Spyder project settings 99 | .spyderproject 100 | .spyproject 101 | 102 | # Rope project settings 103 | .ropeproject 104 | 105 | # mkdocs documentation 106 | /site 107 | 108 | # mypy 109 | .mypy_cache/ 110 | .dmypy.json 111 | dmypy.json 112 | 113 | # Pyre type checker 114 | .pyre/ 115 | 116 | #my 117 | /apk 118 | .idea 119 | .DS_Store 120 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 已解决的痛点 2 | 1、pageobject分层时,page的组织和层级 3 | 2、元素定位:通过父节点找子节点、通过子节点确定父节点、找兄弟节点 4 | 3、多设备分配测试任务运行 5 | 4、断言相关 6 | 5、日志和报告 7 | 6、业务复用和维护 8 | 9 | 10 | ## 需要安装的 11 | ```brew install allure-commandline``` (生成allure报告的工具) 12 | 13 | 安装requment.txt里面的第三方包 14 | 15 | ``` 16 | selenium==3.14.1 17 | Appium-Python-Client 18 | PyYAML 19 | pytest 20 | allure-pytest 21 | flaky 22 | pytest-sugar 23 | ``` 24 | ## 常用命令 25 | ``` 26 | adb devices 27 | adb kill-server 28 | adb shell "dumpsys window w | grep name=" (获取当前页面的Activity) 29 | ``` 30 | 运行appium服务器(带有日志形式,no-reset形式,多设备时指定连接设备) 31 | 32 | ```appium --address 0.0.0.0 --port 4723 --log "appium.log" --log-timestamp --local-timezone --no-reset --session-override -U 192.168.56.101:5555``` 33 | 34 | 35 | # 快速使用 36 | 37 | ### 检测环境: 38 | 在apk中添加要测的app包 39 | 运行env_check.py检测环境 40 | 41 | ### 原理讲解 42 | **0:分层概念** 43 | page集、page类、page类加载方法(load_android、load_ios)、page元素、元素的属性 44 | **1、配置文件** 45 | 路径: 项目/data/config_android.yaml 46 | 需要修改的有:app包路径、appium版本号、devices相关、报告相关路径 47 | **2、编写pages** 48 | 路径: 项目/pages 49 | **创建一个page集合**,在pageset.py中创建page集合类然后添加类属性page类(page类名为中文,通过注册从而使page类的变量名变成中文) 50 | 注释:最好在page集合类中添加page的层级关系的注释 51 | 52 | ``` 53 | #pageset.py 54 | from .productpage import * 55 | 56 | class ProductPages: 57 | 特卖首页=HomePage() 58 | 分类列表搜索页=CategoryListPage() #上级页为 特卖首页 59 | 搜索后列表页=SearchListPage() #上级页为 分类列表搜索页 60 | 商品详情页=ProductDetailsPage() 61 | ``` 62 | 63 | **创建page类**(继承basepage类),必填属性:name ,实现基类方法:load_android、load_ios (先不用这个) 64 | 65 | **load_android格式**: 66 | ``` 67 | #productpage.py 68 | from base.page import BasePage,get_locator 69 | 70 | class CategoryListPage(BasePage): 71 | 72 | name="分类列表搜索页" 73 | 74 | def load_android(self): 75 | self.activity="com.jumei.list.category.CategoryListActivity" 76 | 77 | self.搜索输入框=get_locator(self.name,"搜索输入框",'id','com.jm.android.jumei:id/search_input') 78 | self.搜索按钮=get_locator(self.name,"搜索按钮",'id','com.jm.android.jumei:id/search_bt') 79 | ``` 80 | get_locator方法返回元素实例(dict),元素包含有属性:page名、元素名、元素定位方式、定位参数、是否是动态(默认为静态),传参时一般只需要传page名、元素名、元素定位方式、定位参数 81 | 82 | **3、编写用例**: 83 | 路径: 项目/test/test_用例组名.py 84 | **上下文**: 85 | 默认必有py文件 **conftest***,这是pytest运行时的上下文环境(setup、teardown),导入的base.conftest 86 | 原理通过pytest.fixture装饰器从而不同作用域下实现setup、teardown, 87 | 已加载 初始化环境、driver的运行环境、用例日志 88 | 89 | 用例组文件下编写用例集合类(test_用例集名),编写用例方法(test_用例名) 90 | 91 | **基础用例**: 92 | ``` 93 | #test_home.py 94 | from base.action import ElementActions 95 | from pages.pageset import ProductPages as p 96 | from base.utils import log 97 | 98 | class TestLogin(): 99 | 100 | 101 | def test_home(self, action: ElementActions): 102 | 103 | action.sleep(8) 104 | 105 | action.start_activity(p.特卖首页.activity)\ 106 | .sleep(4)\ 107 | .click(p.特卖首页.搜索输入框) 108 | 109 | action.text(p.分类列表搜索页.搜索输入框,"迪奥口红")\ 110 | .click(p.分类列表搜索页.搜索按钮) 111 | 112 | action.click(p.搜索后列表页.第一个商品项) 113 | for count in range(20): 114 | if action.swip_down().is_text_displayed("商品参数"): 115 | break 116 | 117 | if action.is_text_displayed("迪奥") ==False: 118 | raise NotFoundTextError 119 | action.sleep(1) 120 | ``` 121 | 122 | 123 | **action封装方法原理**: 124 | click实际就是传入 页面元素参数 ,通过driver.find_element找到后再执行点击事件 125 | text 通过driver.find_element找到后再执行send_key 126 | swip_down向下滑动 127 | is_text_displayed : 判断当前页面是否有对应传参文本 128 | 129 | ## 运行方式: 130 | 1、直接运行run.py 131 | 2、run all case: 132 | ```python3 run.py``` 133 | run one module case: 134 | ```python3 run.py test/test_home.py``` 135 | run case with key word: 136 | ```python3 run.py -k ``` 137 | run class case: 138 | ```python3 run.py test/test_demo.py::Test_demo``` 139 | run class::method case: 140 | ```python3 run.py test/test_demo.py::Test_demo::test_home``` 141 | 142 | ### 待完善 143 | ios兼容 144 | -------------------------------------------------------------------------------- /base/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | -------------------------------------------------------------------------------- /base/conftest_android.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import pytest,os,logging 4 | from appium import webdriver 5 | from base.action import ElementActions 6 | from base.environment import EnvironmentAndroid 7 | from base.utils import log 8 | 9 | 10 | 11 | #pytest的setup和down工作 12 | 13 | 14 | 15 | 16 | #初始化driver对象,在package的领域只会执行一次 17 | @pytest.fixture("package") 18 | def driverenv(): 19 | 20 | 21 | env=EnvironmentAndroid() 22 | current_device=env.current_device 23 | 24 | capabilities = { 25 | 'platformName': current_device.get("platformName"), 26 | 'platformVersion': current_device.get("platformVersion"), 27 | 'deviceName': current_device.get("deviceName"), 28 | 'udid': current_device.get("deviceName"), 29 | 'systemPort':current_device.get('systemPort'), 30 | 'app': env.appium.get("app"), 31 | 'clearSystemFiles': True, 32 | 'appActivity': env.appium.get("appActivity"), 33 | 'appPackage': env.appium.get("appPackage"), 34 | 'automationName': 'UIAutomator2', 35 | 'noSign': True, 36 | 'recreateChromeDriverSessions': True, 37 | "unicodeKeyboard": True, 38 | "noReset":True, 39 | "fullReset":False, 40 | "newCommandTimeout": 300 41 | } 42 | # systemPort=current_device.get('systemPort') 43 | # if systemPort!=None: 44 | # capabilities['systemPort']=systemPort 45 | # 46 | log.info('当前执行的appium相关配置为:'+str(capabilities)) 47 | 48 | host=current_device.get('appiumserver') 49 | 50 | driver = webdriver.Remote(host, capabilities) 51 | 52 | return driver 53 | 54 | 55 | #初始化ElementActions类的对象,在package的领域只会执行一次,并且通过yield实现package执行结束前的数据清理工作 56 | @pytest.fixture("package") 57 | def action(driverenv): 58 | element_action=ElementActions(driverenv) 59 | yield element_action #返回并且挂载ElementActions的实例,在对应作用域结束前,执行driver.quit() 60 | 61 | element_action.driver.quit() 62 | 63 | 64 | 65 | 66 | 67 | #用例执行前后:加入日志说明、结束前的截图输出到报告上 68 | @pytest.fixture(autouse=True) 69 | def caserun(action): 70 | 71 | log.info("————————————————————————执行用例 ----------——————————————" ) 72 | yield 73 | action.sleep(1).get_img("用例结束前的截图") 74 | log.info("————————————————————————该用例执行结束 ----------——————————————") 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /base/conftest_ios.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import pytest 4 | from appium import webdriver 5 | from base.action import ElementActions 6 | from base.environment import EnvironmentIOS 7 | from base.utils import log 8 | import allure 9 | 10 | #pytest的setp和down工作 11 | 12 | 13 | 14 | @pytest.fixture("session") 15 | def env(): 16 | return EnvironmentIOS() 17 | 18 | 19 | 20 | 21 | @pytest.fixture(autouse=True) 22 | def caselog(): 23 | log.info("————————————————————————执行用例 ----------——————————————" ) 24 | yield 25 | log.info("————————————————————————该用例执行结束 ----------——————————————") 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /base/environment.py: -------------------------------------------------------------------------------- 1 | import os,abc,yaml 2 | from base.shell import * 3 | from base.utils import log,singleton 4 | 5 | 6 | 7 | #环境的抽象类 8 | class Environment(metaclass=abc.ABCMeta): 9 | 10 | 11 | @abc.abstractmethod 12 | def check_environment(self): 13 | pass 14 | 15 | @abc.abstractmethod 16 | def get_conf(self): 17 | pass 18 | 19 | 20 | 21 | @singleton 22 | class EnvironmentAndroid(Environment): 23 | def __init__(self): 24 | self.conf=self.get_conf() 25 | self.appium = self.conf.get("appium") #key: apk、appActivity、appPackage、version 26 | self.path=self.conf.get("path") 27 | self.devices=self.conf.get("devices") 28 | 29 | #最开始运行时动态获取,存储suit和device的对应关系 30 | self.current_device={} 31 | 32 | self.current_path=None 33 | 34 | 35 | def get_conf(self): 36 | 37 | environment_info_path = str( 38 | os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, "data/config_android.yaml"))) 39 | 40 | log.info('获取环境配置 Path:' + environment_info_path) 41 | with open(environment_info_path,"r") as f: 42 | conf=yaml.load(f) 43 | 44 | return conf 45 | 46 | def callback_current_device(self,device:dict): 47 | #传入当前的device信息 48 | self.current_device=device 49 | 50 | def callback_current_path(self,current_path): 51 | 52 | self.current_path=current_path 53 | 54 | 55 | 56 | 57 | def check_environment(self): 58 | log.info('检查环境...') 59 | 60 | # 判断是否设置环境变量ANDROID_HOME 61 | if "ANDROID_HOME" in os.environ: 62 | command = os.path.join( 63 | os.environ["ANDROID_HOME"], 64 | "platform-tools", 65 | "adb") 66 | else: 67 | raise EnvironmentError( 68 | "Adb not found in $ANDROID_HOME path: %s." % 69 | os.environ["ANDROID_HOME"]) 70 | 71 | # 检查设备 72 | current_devices = Device.get_android_devices() 73 | if len(current_devices)==0: 74 | log.info('没有设备连接') 75 | exit() 76 | for device in self.devices: 77 | deviceName=device.get("deviceName") 78 | if deviceName in current_devices: 79 | log.info('已正常连接设备{}'.format(deviceName)) 80 | else: 81 | log.error('设备{}未正常连接'.format(deviceName)) 82 | 83 | 84 | 85 | # 检查appium版本 86 | appium_v= Shell.invoke('appium -v') 87 | if self.appium.get("version") not in appium_v: 88 | log.info('appium 版本有问题') 89 | exit() 90 | else: 91 | log.info('appium version {}'.format(appium_v)) 92 | 93 | #检测appium-doctor输出 94 | result=Shell.invoke('appium-doctor').splitlines() 95 | log.info(result) 96 | 97 | @singleton 98 | class EnvironmentIOS(Environment): 99 | pass 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /base/page.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from base.utils import log,Conf,get_attrsname 3 | from base.action import ElementActions 4 | import abc,inspect 5 | 6 | 7 | 8 | 9 | class BasePage(metaclass=abc.ABCMeta): 10 | #抽象类BasePage,不能被实例化,实际使用的子类 11 | #初始化时,通过平台决定加载的元素(实际使用page的元素时,使用对应平台的元素) 12 | 13 | def __init__(self): 14 | conf = Conf() 15 | if conf.platform==conf.androidname: 16 | self.load_android() 17 | elif conf.platform==conf.iosname: 18 | self.load_ios() 19 | else: 20 | raise AttributeError 21 | 22 | name = "" 23 | 24 | @abc.abstractmethod 25 | def load_android(self): 26 | self.activity="" 27 | pass 28 | 29 | 30 | def load_ios(self): 31 | pass 32 | 33 | 34 | #获取定位器对象(字典结构),定位器对象返回的就是元素本身,包含对应元素属性 35 | #元素属性有:元素名、元素的定位方式、对应定位方式的值、是否是动态元素、出现该元素的前置操作(默认为空,填写page类的前置操作方法名)、元素的页面名 36 | def get_locator(self,elename, type, value, dynamic=False,switch=None,page=None): 37 | 38 | if page==None: 39 | page=self.name 40 | locator=dict(name=elename, type=type, value=value, dynamic=dynamic,switch=switch,page=page) 41 | 42 | return locator 43 | 44 | def newlocator(self,locator:dict,map:dict): 45 | #动态修改定位元素方式 46 | for key,value in map.items(): 47 | locator[key]=value 48 | 49 | return locator 50 | 51 | 52 | def pageinto(self,action): 53 | pass 54 | 55 | 56 | 57 | def check_pageset(Pagesset,action: ElementActions): 58 | #参数Pagesset为元素是Pages的list 59 | 60 | for Pages in Pagesset: 61 | 62 | log.info('\n ++++++检测静态页面集: {}++++++\n'.format(Pages.__name__)) 63 | 64 | check_page(Pages,action) 65 | 66 | 67 | 68 | 69 | def check_page(Pages,action: ElementActions): 70 | 71 | #只能检测静态页面,即有固定进入方法的:pageinto 72 | 73 | pagesname_list=get_attrsname(Pages) 74 | 75 | for page_name in pagesname_list: 76 | page=getattr(Pages,page_name) 77 | 78 | 79 | #如果为静态页面时可通过page的跳转方法进入对应页面 80 | if hasattr(page,'pageinto')==False: 81 | continue 82 | else: 83 | log.info(' ----检测静态页面: {}----'.format(page_name)) 84 | elements_name = get_attrsname(page) 85 | getattr(page,'pageinto')(action) 86 | 87 | # 对元素进行遍历查询 88 | for element_name in elements_name: 89 | element=getattr(page,element_name) 90 | if isinstance(element,dict): 91 | if element.get('dynamic')==False: 92 | if element.get('switch')!=None: 93 | #如果该元素在当前页面有前置步骤,则执行该前置步骤 94 | getattr(page,element.get('switch'))(action) 95 | 96 | action.is_element_exist(locator=element) 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /base/run.py: -------------------------------------------------------------------------------- 1 | from base.shell import Shell 2 | from base.utils import log,Conf,ls_by_key,Logbuilder 3 | from base.environment import EnvironmentAndroid 4 | import os,jprops,allure,pytest,logging 5 | from multiprocessing import Pool 6 | 7 | 8 | class Run(): 9 | 10 | def __init__(self,platform=Conf().androidname): 11 | 12 | self.conf=Conf() 13 | self.platform=platform 14 | self.conf.set_platform(platform) # 设置执行平台 15 | 16 | self.env=EnvironmentAndroid() 17 | self.devices=self.env.devices 18 | 19 | 20 | self.xml_report_path =os.path.join(self.env.path.get("report"),'xml') 21 | self.html_report_path = os.path.join(self.env.path.get("report"),'html') 22 | self.properties_path=os.path.join(self.xml_report_path,'environment.properties') 23 | 24 | def get_run_args(self): 25 | 26 | #配置用于输出到报告的日志格式 27 | 28 | log_format = '--log-format=%(levelname)s %(asctime)s %(message)s \n'.format() 29 | log_date_format = '--log-date-format=%H:%M:%S' 30 | log_level='--log-level={}'.format(str(logging.INFO)) 31 | 32 | 33 | args = ['-s', '-q',log_format,log_date_format,log_level,'--alluredir', self.xml_report_path, "--verbose"] 34 | 35 | return args 36 | 37 | def generate_report(self): 38 | 39 | #给报告中添加执行环境信息 40 | env_dict={} 41 | 42 | env=self.env.conf 43 | 44 | #修改把yaml格式改成对应的键值对 45 | devices=env.get('devices') 46 | env.pop('devices') 47 | new_env=dict(env, **devices) 48 | 49 | env_dict.update(new_env) 50 | env_dict.update(self.conf.info) 51 | 52 | 53 | env_properties = {} 54 | 55 | for key0,value0 in env_dict.items(): 56 | for key,value in value0.items(): 57 | env_properties['{}.{}'.format(key0,key)]=str(value) 58 | 59 | try: 60 | with open( self.properties_path,'w',encoding='utf-8') as fp: 61 | jprops.store_properties(fp, env_properties) 62 | except: 63 | log.error('配置环境未输出到报告中') 64 | 65 | #执行生成报告命令 66 | cmd = 'allure generate %s -o %s --clean' % (self.xml_report_path, self.html_report_path) 67 | try: 68 | Shell.invoke(cmd) 69 | log.info("测试报告成功生成") 70 | except: 71 | log.error("Html测试报告生成失败,确保已经安装了Allure-Commandline") 72 | 73 | 74 | 75 | 76 | def exec(self,sys_argv): 77 | 78 | 79 | if len(sys_argv) != 0: 80 | self._exec_pytest(sys_argv) 81 | 82 | else: 83 | dir_tests = os.path.basename(self.env.path.get('tests')) 84 | scheduling_info = self._scheduling_process() 85 | 86 | pool=Pool(len(scheduling_info)) 87 | 88 | for device_key,suitlist_value in scheduling_info.items(): 89 | 90 | testsuite_paths=[] 91 | current_device=self.env.devices.get(device_key) 92 | 93 | for suit in suitlist_value: 94 | testsuite_paths.append(os.path.join(dir_tests,suit)) 95 | 96 | try: 97 | pool.apply_async(self._batch_exec_pytest,args=(self.platform,current_device,testsuite_paths)) 98 | except Exception as e: 99 | raise ChildProcessError 100 | 101 | pool.close() 102 | pool.join() 103 | 104 | 105 | def _exec_pytest(self,sys_argv): 106 | #读取命令行参数,单设备执行 107 | args = sys_argv + self.get_run_args() 108 | 109 | 110 | #清除log对象已有的handler 111 | for handle in log.handlers: 112 | log.removeHandler(handle) 113 | 114 | # 定义handler的输出格式 115 | formatter = logging.Formatter('%(levelname)s %(message)s'.format(os.getpid()), "%H:%M:%S") 116 | 117 | #添加用于输出到控制台的handler 118 | console_handler=Logbuilder().get_consolehandler(formatter) 119 | log.addHandler(console_handler) 120 | 121 | current_device=self.env.devices.get('device1') 122 | # 当前进程的环境对象通过回调写入current_device 123 | self.env.callback_current_device(current_device) 124 | 125 | pytest.main(args) 126 | 127 | 128 | 129 | @staticmethod 130 | def _batch_exec_pytest(platform,current_device,testsuite_paths): 131 | # 通过多进程调度执行用例(多台设备) 132 | #testsuite_paths 为list ,格式为[tests/test_suit2,tests/test_suit3] 133 | 134 | log.info('Run task pid={} testsuite_paths: {}...'.format(os.getpid(), testsuite_paths)) 135 | 136 | #清除log对象已有的handler 137 | for handle in log.handlers: 138 | log.removeHandler(handle) 139 | 140 | # 定义handler的输出格式 141 | formatter = logging.Formatter('pid:{} %(levelname)s %(message)s'.format(os.getpid()), "%H:%M:%S") 142 | 143 | #添加用于输出到控制台的handler 144 | console_handler=Logbuilder().get_consolehandler(formatter) 145 | 146 | log.addHandler(console_handler) 147 | 148 | 149 | run=Run(platform) 150 | 151 | #当前进程的环境对象通过回调写入current_device 152 | run.env.callback_current_device(current_device) 153 | 154 | #导入参数执行pytest 155 | args=testsuite_paths+run.get_run_args() 156 | 157 | pytest.main(args) 158 | 159 | 160 | 161 | 162 | 163 | def _scheduling_process(self): 164 | #给多台设备分配测试任务的调度算法(简单平均调度) 165 | #其中suit1是文件夹的名字、device1是配置中device设备的key 166 | 167 | """ 168 | :return: 169 | { 170 | device1:[suit1,suit2] 171 | device2:[suit3,suit4] 172 | device3:[suit5] 173 | } 174 | 175 | """ 176 | 177 | tests_path=self.env.path.get('tests') 178 | suitname_list=ls_by_key(tests_path,'test') 179 | 180 | 181 | if len(suitname_list)==0 or len(self.devices)==0: 182 | raise IndexError('data is bad') 183 | 184 | task_num,mod =divmod(len(suitname_list),len(self.devices)) 185 | 186 | suitname_list_slice=[] 187 | tmp=[] 188 | count=0 189 | for suitname in suitname_list: 190 | tmp.append(suitname) 191 | if count<(len(suitname_list)-mod): 192 | if len(tmp)==task_num: 193 | suitname_list_slice.append(tmp) 194 | tmp=[] 195 | count+=1 196 | 197 | #对最后一个加入整除后剩余的 198 | last_ele=suitname_list_slice[-1] 199 | suitname_list_slice[-1]=last_ele+tmp 200 | 201 | 202 | scheduling_info={} 203 | count=0 204 | for device_key in self.devices: 205 | scheduling_info[device_key]=suitname_list_slice[count] 206 | count=count+1 207 | 208 | log.info("多设备分配的测试集执行为: {}\n".format(str(scheduling_info))) 209 | 210 | 211 | return scheduling_info 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /base/shell.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os,sys,pytest 3 | from base.utils import log 4 | from base.environment import EnvironmentAndroid 5 | 6 | import subprocess 7 | 8 | 9 | 10 | 11 | #Device类,用get_android_devices返回执行adb devices命令时的devices信息(即获取当前链接的机子devicename) 12 | class Device: 13 | @staticmethod 14 | def get_android_devices(): 15 | android_devices_list = [] 16 | for device in Shell.invoke('adb devices').splitlines(): 17 | if 'device' in device and 'devices' not in device: 18 | device = device.split('\t')[0] 19 | android_devices_list.append(device) 20 | return android_devices_list 21 | 22 | 23 | 24 | class Shell: 25 | @staticmethod 26 | def invoke(cmd,cwd=None,is_log=True): 27 | # shell设为true,程序将通过shell来执行 28 | # stdin, stdout, stderr分别表示程序的标准输入、输出、错误句柄。 29 | # 他们可以是PIPE,文件描述符或文件对象,也可以设置为None,表示从父进程继承。 30 | # subprocess.PIPE实际上为文本流提供一个缓存区 31 | if is_log==True: 32 | log.info("执行命令: {}".format(cmd)) 33 | p= subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,cwd=cwd) 34 | output, errors=p.communicate() 35 | o = output.decode("utf-8") 36 | return o 37 | 38 | # 判断是否设置环境变量ANDROID_HOME 39 | if "ANDROID_HOME" in os.environ: 40 | command = os.path.join( 41 | os.environ["ANDROID_HOME"], 42 | "platform-tools", 43 | "adb") 44 | else: 45 | raise EnvironmentError( 46 | "Adb not found in $ANDROID_HOME path: %s." % 47 | os.environ["ANDROID_HOME"]) 48 | 49 | 50 | 51 | class ADB: 52 | """ 53 | 参数: device_id 54 | """ 55 | 56 | def __init__(self, device_id=""): 57 | 58 | if device_id == "": 59 | self.device_id = "" 60 | else: 61 | self.device_id = "-s %s" % device_id 62 | 63 | def adb(self, args): 64 | cmd = "%s %s %s" % (command, self.device_id, str(args)) 65 | return Shell.invoke(cmd) 66 | 67 | def shell(self, args): 68 | cmd = "%s %s shell %s" % (command, self.device_id, str(args),) 69 | return Shell.invoke(cmd) 70 | 71 | def get_device_state(self): 72 | """ 73 | 获取设备状态: offline | bootloader | device 74 | """ 75 | return self.adb("get-state").stdout.read().strip() 76 | 77 | def get_device_id(self): 78 | """ 79 | 获取设备id号,return serialNo 80 | """ 81 | return self.adb("get-serialno").stdout.read().strip() 82 | 83 | def get_android_version(self): 84 | """ 85 | 获取设备中的Android版本号,如4.2.2 86 | """ 87 | return self.shell( 88 | "getprop ro.build.version.release").strip() 89 | 90 | def get_sdk_version(self): 91 | """ 92 | 获取设备SDK版本号 93 | """ 94 | return self.shell("getprop ro.build.version.sdk").strip() 95 | 96 | 97 | -------------------------------------------------------------------------------- /base/utils.py: -------------------------------------------------------------------------------- 1 | import logging,os,yaml,copy,time 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | #单例装饰器 10 | def singleton(class_): 11 | instances = {} 12 | 13 | def getinstance(*args, **kwargs): 14 | if class_ not in instances: 15 | instances[class_] = class_(*args, **kwargs) 16 | return instances[class_] 17 | 18 | return getinstance 19 | 20 | @singleton 21 | class Conf(): 22 | def __init__(self): 23 | self.config_path = str(os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, "data/config.yaml"))) 24 | self.info=self.get_info() 25 | self.androidname='android' 26 | self.iosname='ios' 27 | self.platform=self.info.get('platform')['run'] 28 | 29 | def get_info(self): 30 | 31 | with open(self.config_path, "r") as f: 32 | info = yaml.load(f) 33 | return info 34 | 35 | def set_info(self): 36 | with open(self.config_path, "w") as f: 37 | yaml.dump(self.info,f) 38 | 39 | def set_platform(self,platform): 40 | log.info("设置平台为:{}".format(platform)) 41 | d=copy.deepcopy(self.info) 42 | d['platform']['run']=platform 43 | self.info=d 44 | self.set_info() 45 | 46 | return platform 47 | 48 | 49 | @singleton 50 | class ArgsData(): 51 | def __init__(self): 52 | self.config_path = str(os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, "data/args_data.yaml"))) 53 | self.info = self.get_info() 54 | self.users=self.info.get('users') 55 | 56 | def get_info(self): 57 | 58 | with open(self.config_path, "r") as f: 59 | info = yaml.load(f) 60 | return info 61 | 62 | def set_info(self): 63 | with open(self.config_path, "w") as f: 64 | yaml.dump(self.info,f) 65 | 66 | 67 | 68 | class Logbuilder(): 69 | def __init__(self, loggername='log',loglevel=None): 70 | 71 | self.loggername=loggername 72 | 73 | 74 | 75 | def get_consolehandler(self,formatter): 76 | 77 | 78 | #创建一个handler,添加handler,用于输出到控制台 79 | console_handler = logging.StreamHandler() 80 | console_handler.setLevel(logging.INFO) 81 | console_handler.setFormatter(formatter) 82 | 83 | return console_handler 84 | 85 | 86 | def getlog(self): 87 | 88 | # 创建一个logger 89 | self.logger = logging.getLogger(self.loggername) 90 | self.logger.setLevel(logging.INFO) 91 | 92 | # 定义handler的输出格式 93 | formatter = logging.Formatter(' \n %(message)s', 94 | "%H:%M:%S") 95 | 96 | console_handler=self.get_consolehandler(formatter) 97 | 98 | self.logger.addHandler(console_handler) 99 | 100 | return self.logger 101 | 102 | 103 | log=Logbuilder("log:").getlog() 104 | 105 | 106 | 107 | def get_attrsname(obj): 108 | #获取当前对象的非私有的属性名字列表 109 | 110 | attrs=[attr for attr in dir(obj) if not callable(attr) and not attr.startswith("__")] 111 | 112 | return attrs 113 | 114 | 115 | class Waittime_count: 116 | #用于计算一个步骤的执行时间,如果超出规定时间就输出日志 117 | 118 | def __init__(self,msg="等待时间有:",durationtime=3): 119 | self.msg=msg 120 | self.starttime=None 121 | self.endtime=None 122 | self.durationtime=durationtime 123 | 124 | 125 | def start(self): 126 | self.starttime=time.time() 127 | 128 | def end(self): 129 | self.endtime=time.time() 130 | Waittime=round(self.starttime - self.endtime, 2) 131 | if Waittime>self.durationtime: 132 | log.info(self.msg+" {}s ".format(Waittime)) 133 | 134 | 135 | 136 | def ls_by_key(path:str,key:str): 137 | #获取当前路径下,通过ls命令获取的文件或文件夹名的列表,过滤条件为对应的key参数 138 | #输出list 139 | from base.shell import Shell 140 | 141 | result=[] 142 | out=Shell.invoke('ls',cwd=path,is_log=False) 143 | 144 | for ele in out.splitlines(): 145 | if key in ele: 146 | result.append(ele) 147 | 148 | return result 149 | -------------------------------------------------------------------------------- /base/verify.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import re 3 | from base.utils import log 4 | 5 | class NotFoundElementError(Exception): 6 | pass 7 | 8 | 9 | class NotFoundTextError(Exception): 10 | pass 11 | 12 | 13 | class NumError(Exception): 14 | pass 15 | 16 | 17 | 18 | 19 | 20 | 21 | class Assert(): 22 | 23 | def _raise_exception(self, msg): 24 | 25 | raise AssertionError(msg) 26 | 27 | 28 | def assert_true(self, condition, msg=None,logmsg=''): 29 | if not condition: 30 | self._raise_exception(msg) 31 | else: 32 | log.info("断言成功: {}".format(logmsg)) 33 | 34 | def assert_false(self, false_condition, msg=None,logmsg=''): 35 | if false_condition: 36 | self._raise_exception(msg) 37 | else: 38 | log.info("断言成功: {}".format(logmsg)) 39 | 40 | def assert_equals(self, expected, actual, msg=None,logmsg=''): 41 | self.assert_true(expected == actual, msg,logmsg) 42 | 43 | assert_eq = assert_equals 44 | 45 | def assert_not_equals(self, expected, actual, msg=None,logmsg=''): 46 | self.assert_true(expected != actual, msg,logmsg) 47 | 48 | assert_ne = assert_not_equals 49 | 50 | 51 | def assert_in(self, member, container, msg=None,logmsg=''): 52 | self.assert_true(member in container, msg,logmsg) 53 | 54 | def assert_not_in(self, member, container, msg=None,logmsg=''): 55 | self.assert_true(member not in container, msg,logmsg) 56 | 57 | def assert_greater_than(self, greater, less, msg=None,logmsg=''): 58 | self.assert_true(greater > less, msg,logmsg) 59 | 60 | assert_gt = assert_greater_than 61 | 62 | def assert_greater_than_equals(self, expected, actual, msg=None,logmsg=''): 63 | self.assert_true(actual >= expected, msg,logmsg) 64 | 65 | assert_gte = assert_greater_than_equals 66 | 67 | def assert_less_than_equals(self, expected, actual, msg=None,logmsg=''): 68 | self.assert_true(actual <= expected, msg,logmsg) 69 | 70 | assert_lte = assert_less_than_equals 71 | 72 | 73 | def assert_match(self, pattern, s, flags=0, msg=None,logmsg=''): 74 | """使用 re.match 进行匹配断言测试,注意与 assert_search 的区别 75 | """ 76 | self.assert_true(re.match(pattern, s, flags) is not None, msg,logmsg) 77 | 78 | def assert_full_match(self, pattern, s, flags=0, msg=None,logmsg=''): 79 | """使用 re.fullmatch 进行匹配断言测试""" 80 | self.assert_true(re.fullmatch(pattern, s, flags) is not None, msg,logmsg) 81 | 82 | def assert_search(self, pattern, s, flags=0, msg=None,logmsg=''): 83 | """使用 re.search 进行搜索断言测试""" 84 | self.assert_true(re.search(pattern, s, flags), msg,logmsg) 85 | 86 | 87 | Validator=Assert() -------------------------------------------------------------------------------- /data/apk/jumei.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/data/apk/jumei.apk -------------------------------------------------------------------------------- /data/args_data.yaml: -------------------------------------------------------------------------------- 1 | users: 2 | user1: ["13550234762","tmhrush2233"] 3 | user2: ["13550234762","tmhrush2233"] 4 | 5 | -------------------------------------------------------------------------------- /data/config.yaml: -------------------------------------------------------------------------------- 1 | platform: {run: android} 2 | -------------------------------------------------------------------------------- /data/config_android.yaml: -------------------------------------------------------------------------------- 1 | appium: 2 | app: /Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk 3 | appActivity: com.jm.android.jumei.home.activity.StartActivity 4 | appPackage: com.jm.android.jumei 5 | version: '1.9.1' 6 | # host: http://172.20.11.15:4723/wd/hub 7 | host: http://localhost:4723/wd/hub 8 | 9 | 10 | devices: 11 | device1: 12 | deviceName: 2425a80b 13 | platformName: Android 14 | platformVersion: '8.1.0' 15 | appiumserver: http://localhost:4723/wd/hub 16 | systemPort: 8201 17 | 18 | # device2: 19 | # deviceName: 192.168.56.101:5555 20 | # platformName: Android 21 | # platformVersion: '6.0' 22 | # appiumserver: http://172.20.11.11:4723/wd/hub 23 | # systemPort: 8201 24 | # Resolution: [1080,1920] 25 | 26 | path: 27 | tests: /Users/tmh/PycharmProjects/appauto/tests 28 | report: /Users/tmh/PycharmProjects/appauto/report 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /debug.py: -------------------------------------------------------------------------------- 1 | from base.shell import Shell 2 | from base.utils import ls_by_key 3 | import os 4 | from multiprocessing import Pool 5 | import os, time, random,subprocess 6 | 7 | 8 | 9 | 10 | if __name__=='__main__': 11 | pass 12 | -------------------------------------------------------------------------------- /env_check.py: -------------------------------------------------------------------------------- 1 | from base.shell import Shell 2 | from base.utils import log 3 | from base.environment import EnvironmentAndroid 4 | 5 | 6 | #检测环境和启动appium 7 | 8 | 9 | if __name__ == '__main__': 10 | env=EnvironmentAndroid() 11 | env.check_environment() 12 | 13 | 14 | -------------------------------------------------------------------------------- /lib/pages/buypage.py: -------------------------------------------------------------------------------- 1 | from base.page import BasePage 2 | from base.action import ElementActions 3 | from base.utils import log 4 | 5 | 6 | 7 | 8 | class BuySettlementPage(BasePage): 9 | 10 | name="结算页" 11 | 12 | 13 | def load_android(self): 14 | 15 | self.结算价格=self.get_locator("结算价格",'id','com.jm.android.jumei:id/tv_PayTotoalPrice') 16 | self.提交订单=self.get_locator("提交订单",'id','com.jm.android.jumei:id/gosubmit_order') 17 | 18 | self.购买数量增加=self.get_locator('购买数量增加','id','com.jm.android.jumei:id/product_num_add') 19 | self.购买数量减少=self.get_locator('购买数量减少','id','com.jm.android.jumei:id/product_num_lower') 20 | 21 | self.现金卷是否可用=self.get_locator('现金卷是否可用','id','com.jm.android.jumei:id/pco_unuse_num') 22 | self.红包是否可用=self.get_locator('红包是否可用','id','com.jm.android.jumei:id/redpaket_use_num') 23 | 24 | self.使用现金卷=self.get_locator('使用现金卷','id','com.jm.android.jumei:id/pco_useBtn') 25 | self.使用红包=self.get_locator('使用红包','id','com.jm.android.jumei:id/use_redpaket_btn') 26 | 27 | 28 | 29 | class PayOrderPage(BasePage): 30 | name = "支付订单页" 31 | 32 | def load_android(self): 33 | self.订单金额=self.get_locator('订单金额','id','com.jm.android.jumei:id/order_price') 34 | self.去支付=self.get_locator('去支付','id','com.jm.android.jumei:id/gosubmit_pay') 35 | self.支付方式选择s=self.get_locator('支付方式选择s','id','com.jm.android.jumei:id/payment_cod_btn') #有多个,按顺序为 支付宝、微信支付 36 | 37 | # 放弃付款弹窗内的 38 | self.去意已决 = self.get_locator('去意已决', 'id', 'com.jm.android.jumei:id/cancel') 39 | self.再想想 = self.get_locator('再想想', 'id', 'com.jm.android.jumei:id/ok') 40 | 41 | 42 | class PayresultPage(BasePage): 43 | name = '支付结果页' 44 | 45 | 46 | 47 | 48 | class MyOrderPage(BasePage): 49 | name = "我的订单页" 50 | 51 | 52 | def load_android(self): 53 | self.交易单号=self.get_locator('交易单号','id','com.jm.android.jumei:id/order_id') #text属性格式: "交易单号 c267608325" 54 | 55 | 56 | #订单项相关 57 | self.订单商品项s=self.get_locator('订单商品项s','id','com.jm.android.jumei:id/root_layout') #有多个 58 | self.订单商品单价格s=self.get_locator('订单商品单价格s','id','com.jm.android.jumei:id/item_price') #有多个 59 | self.立即支付s=self.get_locator('立即支付s','name','立即支付') #有多个 60 | #使用newlocator 61 | self.订单商品名=self.get_locator('订单商品名','xpath','',dynamic=True) 62 | 63 | -------------------------------------------------------------------------------- /lib/pages/productpage.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from base.page import BasePage 4 | from base.action import ElementActions 5 | from base.utils import log 6 | 7 | #元素定位方式尽量不要xpath,容易很慢(Appium对于xpath定位执行效率是比较低的) 8 | #已通过find_elements_by_android_uiautomator实现通过name元素定位 9 | 10 | 11 | class HomePage(BasePage): 12 | 13 | name="特卖首页" 14 | 15 | 16 | def home(self,action:ElementActions): 17 | action.driver.wait_activity(self.activity,8,interval=0.3) 18 | try: 19 | action.click(self.关闭初始化弹出窗,wait=3) 20 | except: 21 | log.info('无弹窗需要关闭,所以不会找到元素 关闭初始化弹出窗') 22 | action.tap(self.关闭初始化浮窗) 23 | 24 | 25 | 26 | def pageinto(self,action:ElementActions): 27 | action.start_activity(self.activity) 28 | 29 | 30 | 31 | 32 | def load_android(self): 33 | self.activity="com.jm.android.jumei.home.activity.NewHomeActivity" 34 | 35 | self.关闭初始化浮窗=self.get_locator('关闭初始化浮窗','tap','891,132') 36 | self.关闭初始化弹出窗=self.get_locator("关闭初始化弹出窗",'id','com.jm.android.jumei:id/image_home_full_close') 37 | 38 | self.搜索输入框=self.get_locator("搜索输入框",'id','com.jm.android.jumei:id/tv_go_search') 39 | 40 | self.导航栏=self.get_locator("导航栏",'id','com.jm.android.jumei:id/home_navigate_tab') 41 | self.导航栏_推荐=self.get_locator("导航栏_推荐",'xpath','//android.widget.TextView[@text="推荐"]') 42 | 43 | self.推荐商品栏=self.get_locator("推荐商品栏",'id','com.jm.android.jumei:id/content_recycle_view') 44 | self.推荐商品栏_商品栏=self.get_locator("推荐商品栏_商品",'class name','android.widget.LinearLayout') 45 | self.商品栏_购物车加入=self.get_locator("商品_购物车加入",'id','com.jm.android.jumei:id/add_cart_iv') 46 | 47 | #元素通过坐标位置点击 48 | self.进入用户中心按钮=self.get_locator('进入用户中心按钮','tap','987,1483') 49 | 50 | 51 | self.发布=self.get_locator('发布','id','com.jm.android.jumei:id/iv_publish_video') 52 | self.发布_上传视频=self.get_locator('上传视频','name','上传视频') 53 | 54 | 55 | def load_ios(self): 56 | self.搜索输入框="4455" 57 | 58 | 59 | class CategoryListPage(BasePage): 60 | 61 | name="分类列表搜索页" 62 | 63 | def pageinto(self, action: ElementActions): 64 | action.start_activity(self.activity).sleep(0.5) 65 | 66 | 67 | def load_android(self): 68 | self.activity="com.jumei.list.category.CategoryListActivity" 69 | 70 | self.搜索输入框=self.get_locator("搜索输入框",'id','com.jm.android.jumei:id/search_input') 71 | self.搜索按钮=self.get_locator("搜索按钮",'id','com.jm.android.jumei:id/search_bt') 72 | 73 | 74 | 75 | 76 | class SearchListPage(BasePage): 77 | 78 | name = "搜索后列表页" 79 | 80 | 81 | def pageinto(self,action:ElementActions,key="专场"): 82 | categorylistpage=CategoryListPage() 83 | categorylistpage.pageinto(action) 84 | action.text(categorylistpage.搜索输入框,key).click(categorylistpage.搜索按钮) 85 | 86 | 87 | def load_android(self): 88 | 89 | #有多个,点击进入商品详情页 90 | self.商品项标题s=self.get_locator("商品项标题",'id','com.jm.android.jumei:id/goods_title',dynamic=True) 91 | 92 | 93 | class ProductDetailsPage(BasePage): 94 | name = "商品详情页" 95 | 96 | 97 | def load_android(self): 98 | 99 | 100 | 101 | self.收藏按钮=self.get_locator('收藏按钮','id','com.jm.android.jumei:id/my_favourite') 102 | self.分享按钮=self.get_locator('分享按钮','id','com.jm.android.jumei:id/share') 103 | 104 | 105 | 106 | self.促销=self.get_locator("促销",'name','促销') #点击后会出现弹窗 107 | self.促销弹窗标题=self.get_locator("促销弹窗标题",'id','com.jm.android.jumei:id/tv_detail_title',dynamic=True) #text 属性为促销 108 | self.促销弹窗关闭 = self.get_locator("促销弹窗关闭", 'id', 'com.jm.android.jumei:id/rl_close',dynamic=True) 109 | 110 | self.运费 = self.get_locator("运费", 'name', '运费') 111 | self.运费跳转页标题=self.get_locator("运费跳转页标题", 'id', 'com.jm.android.jumei:id/title',page='运费说明页') #text属性为 运费 112 | self.运费跳转页关闭 = self.get_locator("运费跳转页关闭", 'id', 'com.jm.android.jumei:id/close_ImgBtn',page='运费说明页') 113 | 114 | 115 | 116 | self.说明 = self.get_locator( "说明", 'name', '说明') 117 | self.说明弹窗标题=self.get_locator("说明弹窗标题", 'id', 'com.jm.android.jumei:id/tv_detail_title') #text 属性为说明 118 | self.说明弹窗关闭=self.get_locator("说明弹窗关闭", 'id', 'com.jm.android.jumei:id/rl_close') 119 | 120 | 121 | #商品参数相关 122 | self.商品参数列表=self.get_locator('商品参数列表','id','com.jm.android.jumei:id/properties_view') 123 | 124 | #返回多个,第一个为商品名称、第二个为品牌 125 | self.商品参数列表_商品参数值s=self.get_locator('商品参数列表_商品参数值s','id',"com.jm.android.jumei:id/goods_value") 126 | 127 | 128 | #购买相关 129 | self.加入购物车 = self.get_locator("加入购物车", 'id', 'com.jm.android.jumei:id/tv_addcart') 130 | self.立即购买 = self.get_locator('立即购买', 'id', 'com.jm.android.jumei:id/tv_directbuy') 131 | 132 | self.购买弹窗=self.get_locator('购买弹窗','id','com.jm.android.jumei:id/sl_root') 133 | self.skus=self.get_locator('sku选择列表_第一个','id','com.jm.android.jumei:id/tv_sku_name') #有多个 134 | self.不支持退货提示弹窗=self.get_locator('不支持退货提示弹窗','id','android:id/content') 135 | self.确认购买=self.get_locator('确认购买','id','com.jm.android.jumei:id/tv_confirm') 136 | 137 | self.购物车列表按钮=self.get_locator('购物车列表按钮','id','com.jm.android.jumei:id/shopcar_left') 138 | self.购物车数量显示=self.get_locator('购物车数量显示','id','com.jm.android.jumei:id/shopcar_number_tv') 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /lib/pages/set.py: -------------------------------------------------------------------------------- 1 | from .productpage import * 2 | from .userpage import * 3 | from .buypage import * 4 | from .vedio import * 5 | from base.utils import Conf 6 | 7 | 8 | #用户中心相关Page集合类 9 | class UserPages: 10 | 登录页=LoginPage() 11 | 用户中心=UserCenterPage() 12 | 浏览记录=BrowseRecordPage() 13 | 设置页=SetAppPage() 14 | 收藏页=FavouritePage() 15 | 16 | 17 | 18 | #商品page集合类(商品主干流程相关的) 19 | class ProductPages: 20 | 特卖首页=HomePage() 21 | 分类列表搜索页=CategoryListPage() #上级页为 特卖首页 22 | 搜索后列表页=SearchListPage() #上级页为 分类列表搜索页 23 | 商品详情页=ProductDetailsPage() 24 | 25 | 26 | class BuyPages: 27 | 我的订单页=MyOrderPage() 28 | 结算页=BuySettlementPage() 29 | 支付订单页=PayOrderPage() 30 | 31 | class VedioPages: 32 | 视频发布页=VideoReleasePage() 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /lib/pages/userpage.py: -------------------------------------------------------------------------------- 1 | from base.page import BasePage 2 | from base.action import ElementActions 3 | from base.utils import log 4 | 5 | 6 | #name方式查询本质是: 7 | # new UiSelector().textContains' + '(\"' + value + '\") 8 | 9 | 10 | 11 | class UserCenterPage(BasePage): 12 | name = '用户中心页' 13 | 14 | 15 | 16 | def pageinto(self,action:ElementActions): 17 | from .set import ProductPages as p 18 | p.特卖首页.pageinto(action) 19 | action.tap(p.特卖首页.进入用户中心按钮) 20 | 21 | 22 | def is_logined(self,action:ElementActions): 23 | #已登陆时返回True 24 | 25 | if action.find_ele(self.注册登陆,wait=2)!=None: 26 | return False 27 | else: 28 | return True 29 | 30 | 31 | 32 | def load_android(self): 33 | 34 | self.设置按钮=self.get_locator('设置按钮','id','com.jm.android.jumei:id/mine_top_setting_iv') 35 | self.注册登陆=self.get_locator('注册登陆','id','com.jm.android.jumei:id/mine_top_register_login_tv') 36 | 37 | self.顶部=self.get_locator('顶部','id','com.jm.android.jumei:id/mine_top_logined_ll') 38 | self.顶部名字=self.get_locator('顶部名字','xpath','.//android.widget.TextView[contains(@text, "我的")]') 39 | self.用户中心列表=self.get_locator('用户中心列表','id','com.jm.android.jumei:id/mine_card_parent_ll') 40 | self.用户中心列表_列表1=self.get_locator('用户中心列表_列表1','id','com.jm.android.jumei:id/mine_card_content') #查询出多个中的第一个 41 | 42 | 43 | # 查询出多个元素,text属性表示数量,第一个收藏数量、第二个为收藏专柜数量、第三个为浏览记录数量 44 | self.用户中心列表_列表1_相关数量=self.get_locator('相关数量','id', 45 | 'com.jm.android.jumei:id/mine_card_content_item_title_tv') 46 | self.收藏商品=self.get_locator('收藏商品','name','收藏商品') 47 | 48 | self.收藏专柜=self.get_locator('收藏专柜','name','收藏专柜') 49 | 50 | self.浏览记录=self.get_locator('浏览记录','name','浏览记录') 51 | 52 | 53 | #订单 54 | self.查看全部订单=self.get_locator('查看全部订单','id','com.jm.android.jumei:id/more_card_label_url_tv') 55 | self.待付款=self.get_locator('待付款','name','待付款') 56 | self.待发货=self.get_locator('待发货','name','待发货') 57 | 58 | 59 | class BrowseRecordPage(BasePage): 60 | name="浏览记录页" 61 | 62 | def load_android(self): 63 | #value为空,通过newlocator获取该locator 64 | self.当前浏览商品=self.get_locator('当前浏览商品','name','') 65 | self.编辑=self.get_locator('编辑','name','编辑',dynamic=True) 66 | 67 | #返回多个 68 | self.编辑页浏览商品选择按钮=self.get_locator('编辑页浏览商品选择按钮','id','com.jm.android.jumei:id/scan_select',page='浏览记录编辑页') 69 | self.编辑完成=self.get_locator('编辑完成','name','完成',page='浏览记录编辑页') 70 | self.删除=self.get_locator('删除','id','com.jm.android.jumei:id/scan_del',page='浏览记录编辑页') 71 | self.删除弹窗确定按钮=self.get_locator('删除弹窗确定按钮','id','com.jm.android.jumei:id/positive',page='浏览记录编辑页') 72 | 73 | 74 | 75 | class FavouritePage(BasePage): 76 | name = "收藏页" 77 | 78 | def load_android(self): 79 | # value为空,通过newlocator获取该locator 80 | self.当前收藏商品=self.get_locator('当前收藏商品','name','') 81 | 82 | self.删除收藏=self.get_locator('删除收藏','id','com.jm.android.jumei:id/dialog_collect_product_btn_delete') #长按收藏商品时才出现 83 | self.删除收藏取消=self.get_locator('删除收藏取消','id','com.jm.android.jumei:id/dialog_collect_product_btn_cancel') 84 | 85 | 86 | 87 | 88 | 89 | class SetAppPage(BasePage): 90 | name='设置页' 91 | 92 | def pageinto(self,action:ElementActions): 93 | usercenter=UserCenterPage() 94 | usercenter.pageinto(action) 95 | action.click(usercenter.设置按钮) 96 | 97 | 98 | 99 | def load_android(self): 100 | 101 | self.关于聚美按钮 = self.get_locator('关于聚美按钮', 'name', '关于聚美') 102 | self.退出账号=self.get_locator('退出账号','id','com.jm.android.jumei:id/exit_login_btn',dynamic=True) 103 | 104 | self.版本号 = self.get_locator('版本号', 'id', 'com.jm.android.jumei:id/help_vistion', page='设置页-关于聚美',dynamic=True) 105 | self.开发者选项 = self.get_locator('开发者选项', 'name', '开发者选项') 106 | self.后台环境 = self.get_locator('后台环境', 'name', '后台环境', page='设置页-开发者',dynamic=True) 107 | self.测试环境按钮 = self.get_locator('测试环境', 'name', '测试环境', page='设置页-开发者',dynamic=True) 108 | 109 | 110 | 111 | 112 | 113 | class LoginPage(BasePage): 114 | 115 | name="登录页" 116 | 117 | def pageinto(self,action:ElementActions): 118 | action.sleep(0.5).start_activity(self.activity) 119 | usercenterpage=UserCenterPage() 120 | # usercenterpage.pageinto(action) 121 | if action.find_ele(usercenterpage.注册登陆)!=None: 122 | action.click(usercenterpage.注册登陆) 123 | else: 124 | log.info('app已是登陆状态,无法进入登陆页') 125 | 126 | 127 | def login(self,action:ElementActions,account,password): 128 | self.switch_密码登录tag(action) 129 | action.text(self.账号输入框,account).text(self.密码输入框,password).click(self.登录按钮) 130 | action.sleep(5) 131 | 132 | def switch_密码登录tag(self,action:ElementActions): 133 | action.click(self.密码登录tag) 134 | 135 | 136 | def load_android(self): 137 | self.activity="com.jumei.login.loginbiz.activities.login.LoginActivity" 138 | 139 | self.密码登录tag=self.get_locator("密码登录tag",'id','com.jm.android.jumei:id/tab_login_account') 140 | 141 | self.账号输入框=self.get_locator("账号输入框",'id','com.jm.android.jumei:id/lg_user_name',switch='switch_密码登录tag') 142 | self.密码输入框=self.get_locator( "密码输入框", 'id', 'com.jm.android.jumei:id/lg_password',switch='switch_密码登录tag') 143 | self.登录按钮=self.get_locator("登录按钮", 'id', 'com.jm.android.jumei:id/login_account',switch='switch_密码登录tag') 144 | 145 | 146 | def load_ios(self): 147 | self.账号输入框="4455" 148 | -------------------------------------------------------------------------------- /lib/pages/vedio.py: -------------------------------------------------------------------------------- 1 | from base.page import BasePage 2 | from base.action import ElementActions 3 | from base.utils import log 4 | 5 | 6 | 7 | class VideoReleasePage(BasePage): 8 | name="视频发布页" 9 | 10 | def load_android(self): 11 | 12 | #有多个,通过index来选择视频 13 | self.视频选择=self.get_locator('视频选择','id','com.jm.android.jumei:id/iv_thumb') 14 | 15 | self.视频选择后下一步=self.get_locator('选择后下一步','id','com.jm.android.jumei:id/save_button1') 16 | self.视频处理后下一步 = self.get_locator('处理后下一步', 'id', 'com.jm.android.jumei:id/btn_next') 17 | self.视频发布=self.get_locator('视频发布','id','com.jm.android.jumei:id/social_publish_submit') 18 | self.视频描述=self.get_locator('视频描述','id','com.jm.android.jumei:id/social_input_txt') 19 | -------------------------------------------------------------------------------- /lib/reuse_business/base_business.py: -------------------------------------------------------------------------------- 1 | 2 | from base.action import ElementActions 3 | from base.utils import log,ArgsData 4 | from lib.pages.set import ProductPages as p,UserPages as up 5 | 6 | 7 | 8 | 9 | def login(action:ElementActions,user='user1'): 10 | """ 11 | 让app处于登陆状态,已登陆时则不登陆,登陆后处于在用户中心页 12 | 默认使用args_data中的user1登陆 13 | """ 14 | 15 | up.用户中心.pageinto(action) 16 | if up.用户中心.is_logined(action) == False: 17 | action.click(up.用户中心.注册登陆) 18 | 19 | user = ArgsData().users.get(user) 20 | up.登录页.login(action, user[0],user[1]) 21 | log.info('登陆成功') 22 | else: 23 | log.info('app已登陆') 24 | 25 | 26 | 27 | def logout(action:ElementActions): 28 | """让app处于登出状态,未登陆则不操作, 登出后处于用户中心页""" 29 | 30 | up.用户中心.pageinto(action) 31 | if up.用户中心.is_logined(action) == True: 32 | action.click(up.用户中心.设置按钮) 33 | action.click(up.设置页.退出账号) 34 | log.info('登出成功') 35 | else: 36 | log.info('app已登出') 37 | 38 | 39 | 40 | 41 | def set_appenv(action:ElementActions): 42 | # 设置环境为测试环境 43 | 44 | up.设置页.pageinto(action) 45 | 46 | if not action.is_text_displayed('开发者选项'): 47 | log.info('没有开发者选项,先启动调试模式~') 48 | 49 | action.click(up.设置页.关于聚美按钮) 50 | 51 | action.click(up.设置页.版本号, count=8) 52 | 53 | for index in range(2): 54 | action.click(up.设置页.版本号) 55 | if action.is_toast_show('调试', wait=3) != False: 56 | break 57 | action.back_press() 58 | 59 | action.click(up.设置页.开发者选项) 60 | if action.is_text_displayed('测试环境') == True: 61 | log.info('环境已设置为测试环境') 62 | else: 63 | action.click(up.设置页.后台环境) 64 | action.sleep(1).click(up.设置页.测试环境按钮) 65 | action.sleep(5) 66 | log.info('切换到测试环境成功') 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /lib/reuse_business/shopping_business.py: -------------------------------------------------------------------------------- 1 | from base.action import ElementActions 2 | from base.utils import log,ArgsData 3 | from lib.pages.set import ProductPages as p,UserPages as up 4 | from base.verify import NotFoundElementError 5 | 6 | 7 | def browseproduct(action:ElementActions,key='专场',position=0): 8 | p.搜索后列表页.pageinto(action,key) 9 | # 点击对应position的商品 10 | action.sleep(1).click_ele(action.find_ele(p.搜索后列表页.商品项标题s, is_Multiple=True)[position]).sleep(2) 11 | 12 | productname_ele = None 13 | for index in range(10): 14 | action.swip_down() 15 | tmpele = action.find_ele(p.商品详情页.商品参数列表) 16 | goods_value_eles = action.find_ele_child(tmpele, p.商品详情页.商品参数列表_商品参数值s, is_Multiple=True, wait=3) 17 | if len(goods_value_eles) > 0: 18 | productname_ele = goods_value_eles[0] 19 | break 20 | if productname_ele == None: 21 | raise NotFoundElementError 22 | 23 | action.get_img('商品详情页') 24 | productname = action.get_text_ele(productname_ele) 25 | 26 | return productname -------------------------------------------------------------------------------- /report/html/data/attachments/184e4b9f713ed749.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/184e4b9f713ed749.txt -------------------------------------------------------------------------------- /report/html/data/attachments/1b054209eb500c1e.txt: -------------------------------------------------------------------------------- 1 | INFO 12:03:33 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': 'True', 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} -------------------------------------------------------------------------------- /report/html/data/attachments/2009125f090a36cc.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/2009125f090a36cc.txt -------------------------------------------------------------------------------- /report/html/data/attachments/21c2d6d39434b83c.txt: -------------------------------------------------------------------------------- 1 | INFO 12:03:25 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': 'True', 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} -------------------------------------------------------------------------------- /report/html/data/attachments/32919f953a11695e.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/32919f953a11695e.txt -------------------------------------------------------------------------------- /report/html/data/attachments/364443a71485466e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/364443a71485466e.png -------------------------------------------------------------------------------- /report/html/data/attachments/36d231cb37c04a17.txt: -------------------------------------------------------------------------------- 1 | INFO 12:01:08 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': 'True', 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} -------------------------------------------------------------------------------- /report/html/data/attachments/39bdf573c49e6278.txt: -------------------------------------------------------------------------------- 1 | INFO 12:00:41 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': 'True', 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} -------------------------------------------------------------------------------- /report/html/data/attachments/3b5d712ca2cfa385.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/3b5d712ca2cfa385.txt -------------------------------------------------------------------------------- /report/html/data/attachments/3de4c5abcaa50cb.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/3de4c5abcaa50cb.txt -------------------------------------------------------------------------------- /report/html/data/attachments/4415a145575fd6d8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/4415a145575fd6d8.png -------------------------------------------------------------------------------- /report/html/data/attachments/5337e0bfb50b06c0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/5337e0bfb50b06c0.png -------------------------------------------------------------------------------- /report/html/data/attachments/587194d88e90bdd5.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/587194d88e90bdd5.txt -------------------------------------------------------------------------------- /report/html/data/attachments/6404365aaa5f191a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/6404365aaa5f191a.png -------------------------------------------------------------------------------- /report/html/data/attachments/650bb9c791a42f2e.txt: -------------------------------------------------------------------------------- 1 | INFO 14:26:51 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': True, 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} 2 | 3 | INFO 14:27:10 start_activity: com.jm.android.jumei.home.activity.NewHomeActivity 4 | 5 | INFO 14:27:24 通过坐标(987.0,1483.0), 成功点击 页面【特卖首页】的元素【进入用户中心按钮】 6 | 7 | INFO 14:27:26 查找 页面【用户中心页】的元素【注册登陆】 8 | 9 | INFO 14:27:29 app已登陆 10 | 11 | INFO 14:27:29 start_activity: com.jm.android.jumei.home.activity.NewHomeActivity 12 | 13 | INFO 14:27:43 ————————————————————————执行用例 ----------—————————————— 14 | INFO 14:27:43 [点击] 页面【特卖首页】的元素【发布】 15 | 16 | INFO 14:27:45 [点击] 页面【视频发布页】的元素【发布】 17 | 18 | ERROR 14:27:50 【视频发布页】页面中未能找到元素【发布】 19 | locator: 20 | {'name': '发布', 'type': 'id', 'value': 'com.jm.android.jumei:id/social_publish_submit', 'dynamic': False, 'switch': None, 'page': '视频发布页'} 21 | INFO 14:27:50 sleep等待 1 s 22 | 23 | INFO 14:27:52 ————————————————————————该用例执行结束 ----------—————————————— -------------------------------------------------------------------------------- /report/html/data/attachments/69de7f3952a72a0d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/69de7f3952a72a0d.png -------------------------------------------------------------------------------- /report/html/data/attachments/6c7820d70b256863.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/6c7820d70b256863.txt -------------------------------------------------------------------------------- /report/html/data/attachments/6d704f1e86ebd4df.txt: -------------------------------------------------------------------------------- 1 | INFO 12:04:55 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': True, 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} -------------------------------------------------------------------------------- /report/html/data/attachments/71e3657056b93481.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/71e3657056b93481.txt -------------------------------------------------------------------------------- /report/html/data/attachments/79434b6d979f4894.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/79434b6d979f4894.txt -------------------------------------------------------------------------------- /report/html/data/attachments/79eb5a8782924b4e.txt: -------------------------------------------------------------------------------- 1 | INFO 12:05:22 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': True, 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} 2 | 3 | INFO 12:05:35 start_activity: com.jm.android.jumei.home.activity.NewHomeActivity 4 | 5 | INFO 12:05:49 通过坐标(987.0,1483.0), 成功点击 页面【特卖首页】的元素【进入用户中心按钮】 6 | 7 | INFO 12:05:51 查找 页面【用户中心页】的元素【注册登陆】 8 | 9 | INFO 12:05:53 app已登陆 10 | 11 | INFO 12:05:53 start_activity: com.jm.android.jumei.home.activity.NewHomeActivity 12 | 13 | INFO 12:06:07 ————————————————————————执行用例 ----------—————————————— 14 | INFO 12:06:07 [点击] 页面【特卖首页】的元素【发布】 15 | 16 | INFO 12:06:10 [点击] 页面【视频发布页】的元素【发布】 17 | 18 | ERROR 12:06:15 【视频发布页】页面中未能找到元素【发布】 19 | locator: 20 | {'name': '发布', 'type': 'id', 'value': 'com.jm.android.jumei:id/social_publish_submit', 'dynamic': False, 'switch': None, 'page': '视频发布页'} 21 | INFO 12:06:15 sleep等待 1 s 22 | 23 | INFO 12:06:16 ————————————————————————该用例执行结束 ----------—————————————— -------------------------------------------------------------------------------- /report/html/data/attachments/7e6ae649c1b6df2a.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/7e6ae649c1b6df2a.txt -------------------------------------------------------------------------------- /report/html/data/attachments/822a05989c58a85b.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/822a05989c58a85b.txt -------------------------------------------------------------------------------- /report/html/data/attachments/9e3c4826300de3ad.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/9e3c4826300de3ad.txt -------------------------------------------------------------------------------- /report/html/data/attachments/a007d84425b5bb63.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/a007d84425b5bb63.png -------------------------------------------------------------------------------- /report/html/data/attachments/a2fef45cfac7b88.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/a2fef45cfac7b88.png -------------------------------------------------------------------------------- /report/html/data/attachments/ab8981d949a2bb34.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/ab8981d949a2bb34.txt -------------------------------------------------------------------------------- /report/html/data/attachments/ab94871d11b3a4c2.txt: -------------------------------------------------------------------------------- 1 | INFO 12:03:51 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': True, 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} -------------------------------------------------------------------------------- /report/html/data/attachments/aba9b39786212361.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/aba9b39786212361.png -------------------------------------------------------------------------------- /report/html/data/attachments/b449cc3f836fe944.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/b449cc3f836fe944.txt -------------------------------------------------------------------------------- /report/html/data/attachments/b90519268f26a77e.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/b90519268f26a77e.txt -------------------------------------------------------------------------------- /report/html/data/attachments/bb68d42c3a6abca2.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/bb68d42c3a6abca2.txt -------------------------------------------------------------------------------- /report/html/data/attachments/bc1be12f7bde1a6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/bc1be12f7bde1a6.png -------------------------------------------------------------------------------- /report/html/data/attachments/bed1b75cd7491c29.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/bed1b75cd7491c29.txt -------------------------------------------------------------------------------- /report/html/data/attachments/c28d08ff32e6537.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/c28d08ff32e6537.txt -------------------------------------------------------------------------------- /report/html/data/attachments/c354537fab992c28.txt: -------------------------------------------------------------------------------- 1 | INFO 14:39:35 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': True, 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} 2 | 3 | INFO 14:39:45 ————————————————————————执行用例 ----------—————————————— 4 | INFO 14:39:45 [点击] 页面【特卖首页】的元素【发布】 5 | 6 | INFO 14:39:52 [点击] 页面【特卖首页】的元素【上传视频】 7 | 8 | INFO 14:39:54 查找 页面【视频发布页】的元素【视频选择】 9 | 10 | INFO 14:39:55 [点击]1次元素 11 | 12 | INFO 14:39:56 [点击] 页面【视频发布页】的元素【选择后下一步】 13 | 14 | INFO 14:39:58 [点击] 页面【视频发布页】的元素【处理后下一步】 15 | 16 | INFO 14:40:00 sleep等待 7 s 17 | 18 | INFO 14:40:07 [点击] 页面【视频发布页】的元素【视频发布】 19 | 20 | INFO 14:40:25 当前页面成功找到toast: 视频发布成功 21 | 22 | INFO 14:40:25 result: True 23 | 24 | INFO 14:40:26 [点击] 页面【特卖首页】的元素【上传视频】 25 | 26 | INFO 14:40:29 查找 页面【视频发布页】的元素【视频选择】 27 | 28 | INFO 14:40:30 [点击]1次元素 29 | 30 | INFO 14:40:30 [点击] 页面【视频发布页】的元素【选择后下一步】 31 | 32 | INFO 14:40:32 [点击] 页面【视频发布页】的元素【处理后下一步】 33 | 34 | INFO 14:40:34 sleep等待 7 s 35 | 36 | INFO 14:40:41 [点击] 页面【视频发布页】的元素【视频发布】 37 | 38 | INFO 14:40:52 当前页面成功找到toast: 视频发布成功 39 | 40 | INFO 14:40:52 result: True 41 | 42 | INFO 14:40:53 [点击] 页面【特卖首页】的元素【上传视频】 43 | 44 | INFO 14:40:56 查找 页面【视频发布页】的元素【视频选择】 45 | 46 | INFO 14:40:56 [点击]1次元素 47 | 48 | INFO 14:40:57 [点击] 页面【视频发布页】的元素【选择后下一步】 49 | 50 | INFO 14:40:59 [点击] 页面【视频发布页】的元素【处理后下一步】 51 | 52 | INFO 14:41:01 sleep等待 7 s 53 | 54 | INFO 14:41:08 [点击] 页面【视频发布页】的元素【视频发布】 55 | 56 | INFO 14:41:19 当前页面成功找到toast: 视频发布成功 57 | 58 | INFO 14:41:19 result: True 59 | 60 | INFO 14:41:21 [点击] 页面【特卖首页】的元素【上传视频】 61 | 62 | INFO 14:41:24 查找 页面【视频发布页】的元素【视频选择】 63 | 64 | INFO 14:41:24 [点击]1次元素 65 | 66 | INFO 14:41:24 [点击] 页面【视频发布页】的元素【选择后下一步】 67 | 68 | INFO 14:41:27 [点击] 页面【视频发布页】的元素【处理后下一步】 69 | 70 | INFO 14:41:28 sleep等待 7 s 71 | 72 | INFO 14:41:35 [点击] 页面【视频发布页】的元素【视频发布】 73 | 74 | INFO 14:41:49 当前页面成功找到toast: 视频发布成功 75 | 76 | INFO 14:41:49 result: True 77 | 78 | INFO 14:41:50 [点击] 页面【特卖首页】的元素【上传视频】 79 | 80 | INFO 14:41:53 查找 页面【视频发布页】的元素【视频选择】 81 | 82 | INFO 14:41:54 [点击]1次元素 83 | 84 | INFO 14:41:54 [点击] 页面【视频发布页】的元素【选择后下一步】 85 | 86 | INFO 14:41:56 [点击] 页面【视频发布页】的元素【处理后下一步】 87 | 88 | INFO 14:41:58 sleep等待 7 s 89 | 90 | INFO 14:42:05 [点击] 页面【视频发布页】的元素【视频发布】 91 | 92 | INFO 14:42:20 当前页面成功找到toast: 视频发布成功 93 | 94 | INFO 14:42:20 result: True 95 | INFO 14:42:22 sleep等待 1 s 96 | 97 | INFO 14:42:24 ————————————————————————该用例执行结束 ----------—————————————— -------------------------------------------------------------------------------- /report/html/data/attachments/c6d30d954b758685.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/c6d30d954b758685.png -------------------------------------------------------------------------------- /report/html/data/attachments/d292a7adda173007.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/d292a7adda173007.txt -------------------------------------------------------------------------------- /report/html/data/attachments/de9a4d61f65ac32b.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/de9a4d61f65ac32b.txt -------------------------------------------------------------------------------- /report/html/data/attachments/e0c69be8f1448ca3.txt: -------------------------------------------------------------------------------- 1 | INFO 14:38:46 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': True, 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} 2 | 3 | INFO 14:38:57 ————————————————————————执行用例 ----------—————————————— 4 | INFO 14:38:57 [点击] 页面【特卖首页】的元素【发布】 5 | 6 | INFO 14:39:02 [点击] 页面【特卖首页】的元素【上传视频】 7 | 8 | INFO 14:39:05 查找 页面【视频发布页】的元素【视频选择】 9 | INFO 14:39:06 sleep等待 1 s 10 | 11 | INFO 14:39:09 ————————————————————————该用例执行结束 ----------—————————————— -------------------------------------------------------------------------------- /report/html/data/attachments/e3cb25556374b8fc.txt: -------------------------------------------------------------------------------- 1 | INFO 14:36:51 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': True, 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} 2 | 3 | INFO 14:37:01 ————————————————————————执行用例 ----------—————————————— 4 | INFO 14:37:01 [点击] 页面【特卖首页】的元素【发布】 5 | 6 | INFO 14:37:07 [点击] 页面【特卖首页】的元素【上传视频】 7 | 8 | INFO 14:37:10 [点击] 页面【视频发布页】的元素【发布】 9 | 10 | ERROR 14:37:16 【视频发布页】页面中未能找到元素【发布】 11 | locator: 12 | {'name': '发布', 'type': 'id', 'value': 'com.jm.android.jumei:id/social_publish_submit', 'dynamic': False, 'switch': None, 'page': '视频发布页'} 13 | INFO 14:37:16 sleep等待 1 s 14 | 15 | INFO 14:37:19 ————————————————————————该用例执行结束 ----------—————————————— -------------------------------------------------------------------------------- /report/html/data/attachments/e3ce77b42d6a67bc.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/e3ce77b42d6a67bc.txt -------------------------------------------------------------------------------- /report/html/data/attachments/ffff07e22303b196.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/attachments/ffff07e22303b196.txt -------------------------------------------------------------------------------- /report/html/data/behaviors.csv: -------------------------------------------------------------------------------- 1 | "Epic","Feature","Story","FAILED","BROKEN","PASSED","SKIPPED","UNKNOWN" 2 | "","","","0","0","1","0","0" 3 | -------------------------------------------------------------------------------- /report/html/data/behaviors.json: -------------------------------------------------------------------------------- 1 | { 2 | "uid" : "b1a8273437954620fa374b796ffaacdd", 3 | "name" : "behaviors", 4 | "children" : [ { 5 | "name" : "test_case1", 6 | "uid" : "b21acd4f81e0178b", 7 | "parentUid" : "b1a8273437954620fa374b796ffaacdd", 8 | "status" : "passed", 9 | "time" : { 10 | "start" : 1546843185735, 11 | "stop" : 1546843342535, 12 | "duration" : 156800 13 | }, 14 | "flaky" : true, 15 | "parameters" : [ ] 16 | } ] 17 | } -------------------------------------------------------------------------------- /report/html/data/categories.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/data/categories.csv -------------------------------------------------------------------------------- /report/html/data/categories.json: -------------------------------------------------------------------------------- 1 | { 2 | "uid" : "4b4757e66a1912dae1a509f688f20b0f", 3 | "name" : "categories", 4 | "children" : [ ] 5 | } -------------------------------------------------------------------------------- /report/html/data/packages.json: -------------------------------------------------------------------------------- 1 | { 2 | "uid" : "83edc06c07f9ae9e47eb6dd1b683e4e2", 3 | "name" : "packages", 4 | "children" : [ { 5 | "name" : "tests.test_vedio.test_videorelease", 6 | "children" : [ { 7 | "name" : "test_case1", 8 | "uid" : "b21acd4f81e0178b", 9 | "parentUid" : "0ed3e2a4367b18465150d16d910ddf06", 10 | "status" : "passed", 11 | "time" : { 12 | "start" : 1546843185735, 13 | "stop" : 1546843342535, 14 | "duration" : 156800 15 | }, 16 | "flaky" : true, 17 | "parameters" : [ ] 18 | } ], 19 | "uid" : "tests.test_vedio.test_videorelease" 20 | } ] 21 | } -------------------------------------------------------------------------------- /report/html/data/suites.csv: -------------------------------------------------------------------------------- 1 | "Status","Name","Duration in ms","Description" 2 | "passed","tests.test_vedio.test_videorelease.Test_videorelease#test_case1","156800","" 3 | -------------------------------------------------------------------------------- /report/html/data/suites.json: -------------------------------------------------------------------------------- 1 | { 2 | "uid" : "98d3104e051c652961429bf95fa0b5d6", 3 | "name" : "suites", 4 | "children" : [ { 5 | "name" : "tests.test_vedio", 6 | "children" : [ { 7 | "name" : "test_videorelease", 8 | "children" : [ { 9 | "name" : "Test_videorelease", 10 | "children" : [ { 11 | "name" : "test_case1", 12 | "uid" : "b21acd4f81e0178b", 13 | "parentUid" : "d515a6a38946c3b460291a40b998c7f7", 14 | "status" : "passed", 15 | "time" : { 16 | "start" : 1546843185735, 17 | "stop" : 1546843342535, 18 | "duration" : 156800 19 | }, 20 | "flaky" : true, 21 | "parameters" : [ ] 22 | } ], 23 | "uid" : "d515a6a38946c3b460291a40b998c7f7" 24 | } ], 25 | "uid" : "b7d6271ab37e1e88fded0a55ed697df1" 26 | } ], 27 | "uid" : "c1f82c4d30338d8578cbc977fea9ed65" 28 | } ] 29 | } -------------------------------------------------------------------------------- /report/html/data/test-cases/1c34a555846b7834.json: -------------------------------------------------------------------------------- 1 | { 2 | "uid" : "1c34a555846b7834", 3 | "name" : "test_case1", 4 | "fullName" : "tests.test_vedio.test_videorelease.Test_videorelease#test_case1", 5 | "historyId" : "61d0ec5868142760393bb75a0ddaae70", 6 | "time" : { }, 7 | "status" : "broken", 8 | "statusMessage" : "TypeError: 'NoneType' object is not subscriptable", 9 | "statusTrace" : "> lambda: ihook(item=item, **kwds),\n when=when,\n )\n\n/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/flaky/flaky_pytest_plugin.py:273: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\nbase/conftest_android.py:58: in action\n element_action=ElementActions(driverenv)\nbase/utils.py:15: in getinstance\n instances[class_] = class_(*args, **kwargs)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\nself = , driver = \n\n def __init__(self, driver: webdriver.Remote):\n self.driver = driver\n self.env = EnvironmentAndroid()\n #通过driver.get_window_size()获取的分辨率会不准确,所以读取配置的Resolution\n self.Resolution =self.env.current_device.get('Resolution')\n \n if self.Resolution==None:\n Resolution=[1080, 1920]\n \n> self.width =self.Resolution[0]\nE TypeError: 'NoneType' object is not subscriptable\n\nbase/action.py:30: TypeError", 10 | "flaky" : false, 11 | "beforeStages" : [ { 12 | "name" : "action", 13 | "time" : { 14 | "start" : 1546833907614, 15 | "stop" : 1546833907614, 16 | "duration" : 0 17 | }, 18 | "status" : "broken", 19 | "statusMessage" : "TypeError: 'NoneType' object is not subscriptable\n", 20 | "statusTrace" : " File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pluggy/callers.py\", line 187, in _multicall\n res = hook_impl.function(*args)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 969, in pytest_fixture_setup\n result = call_fixture_func(fixturefunc, request, kwargs)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 824, in call_fixture_func\n res = next(it)\n File \"/Users/tmh/PycharmProjects/appauto/base/conftest_android.py\", line 58, in action\n element_action=ElementActions(driverenv)\n File \"/Users/tmh/PycharmProjects/appauto/base/utils.py\", line 15, in getinstance\n instances[class_] = class_(*args, **kwargs)\n File \"/Users/tmh/PycharmProjects/appauto/base/action.py\", line 30, in __init__\n self.width =self.Resolution[0]\n", 21 | "steps" : [ ], 22 | "attachments" : [ ], 23 | "parameters" : [ ], 24 | "stepsCount" : 0, 25 | "attachmentsCount" : 0, 26 | "shouldDisplayMessage" : true, 27 | "hasContent" : true 28 | }, { 29 | "name" : "driverenv", 30 | "time" : { 31 | "start" : 1546833895152, 32 | "stop" : 1546833907614, 33 | "duration" : 12462 34 | }, 35 | "status" : "passed", 36 | "steps" : [ ], 37 | "attachments" : [ ], 38 | "parameters" : [ ], 39 | "stepsCount" : 0, 40 | "attachmentsCount" : 0, 41 | "shouldDisplayMessage" : false, 42 | "hasContent" : false 43 | } ], 44 | "testStage" : { 45 | "status" : "broken", 46 | "statusMessage" : "TypeError: 'NoneType' object is not subscriptable", 47 | "statusTrace" : "> lambda: ihook(item=item, **kwds),\n when=when,\n )\n\n/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/flaky/flaky_pytest_plugin.py:273: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\nbase/conftest_android.py:58: in action\n element_action=ElementActions(driverenv)\nbase/utils.py:15: in getinstance\n instances[class_] = class_(*args, **kwargs)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\nself = , driver = \n\n def __init__(self, driver: webdriver.Remote):\n self.driver = driver\n self.env = EnvironmentAndroid()\n #通过driver.get_window_size()获取的分辨率会不准确,所以读取配置的Resolution\n self.Resolution =self.env.current_device.get('Resolution')\n \n if self.Resolution==None:\n Resolution=[1080, 1920]\n \n> self.width =self.Resolution[0]\nE TypeError: 'NoneType' object is not subscriptable\n\nbase/action.py:30: TypeError", 48 | "steps" : [ ], 49 | "attachments" : [ { 50 | "uid" : "6d704f1e86ebd4df", 51 | "name" : "log", 52 | "source" : "6d704f1e86ebd4df.txt", 53 | "type" : "text/plain", 54 | "size" : 546 55 | }, { 56 | "uid" : "3b5d712ca2cfa385", 57 | "name" : "stdout", 58 | "source" : "3b5d712ca2cfa385.txt", 59 | "type" : "text/plain", 60 | "size" : 0 61 | }, { 62 | "uid" : "71e3657056b93481", 63 | "name" : "stderr", 64 | "source" : "71e3657056b93481.txt", 65 | "type" : "text/plain", 66 | "size" : 0 67 | } ], 68 | "parameters" : [ ], 69 | "stepsCount" : 0, 70 | "attachmentsCount" : 3, 71 | "shouldDisplayMessage" : true, 72 | "hasContent" : true 73 | }, 74 | "afterStages" : [ ], 75 | "labels" : [ { 76 | "name" : "parentSuite", 77 | "value" : "tests.test_vedio" 78 | }, { 79 | "name" : "suite", 80 | "value" : "test_videorelease" 81 | }, { 82 | "name" : "subSuite", 83 | "value" : "Test_videorelease" 84 | }, { 85 | "name" : "host", 86 | "value" : "tangmaoheng-deMacBook-Air.local" 87 | }, { 88 | "name" : "thread", 89 | "value" : "14622-MainThread" 90 | }, { 91 | "name" : "framework", 92 | "value" : "pytest" 93 | }, { 94 | "name" : "language", 95 | "value" : "cpython3" 96 | }, { 97 | "name" : "package", 98 | "value" : "tests.test_vedio.test_videorelease" 99 | }, { 100 | "name" : "resultFormat", 101 | "value" : "allure2" 102 | } ], 103 | "parameters" : [ ], 104 | "links" : [ ], 105 | "hidden" : true, 106 | "retry" : true, 107 | "extra" : { 108 | "categories" : [ ], 109 | "tags" : [ ] 110 | }, 111 | "source" : "1c34a555846b7834.json", 112 | "parameterValues" : [ ] 113 | } -------------------------------------------------------------------------------- /report/html/data/test-cases/2badf96700036808.json: -------------------------------------------------------------------------------- 1 | { 2 | "uid" : "2badf96700036808", 3 | "name" : "test_case1", 4 | "fullName" : "tests.test_vedio.test_videorelease.Test_videorelease#test_case1", 5 | "historyId" : "61d0ec5868142760393bb75a0ddaae70", 6 | "time" : { 7 | "start" : 1546843137419, 8 | "stop" : 1546843146535, 9 | "duration" : 9116 10 | }, 11 | "status" : "broken", 12 | "statusMessage" : "TypeError: 'WebElement' object does not support indexing", 13 | "statusTrace" : "self = , action = \n\n def test_case1(self,action):\n count=5\n action.click(p.特卖首页.发布)\n \n for index in range(count):\n action.click(p.特卖首页.发布_上传视频)\n> videoele=action.find_ele(vp.视频发布页.视频选择)[0]\nE TypeError: 'WebElement' object does not support indexing\n\ntests/test_vedio/test_videorelease.py:19: TypeError", 14 | "flaky" : false, 15 | "beforeStages" : [ { 16 | "name" : "action", 17 | "time" : { 18 | "start" : 1546843137417, 19 | "stop" : 1546843137418, 20 | "duration" : 1 21 | }, 22 | "status" : "passed", 23 | "steps" : [ ], 24 | "attachments" : [ ], 25 | "parameters" : [ ], 26 | "stepsCount" : 0, 27 | "attachmentsCount" : 0, 28 | "shouldDisplayMessage" : false, 29 | "hasContent" : false 30 | }, { 31 | "name" : "driverenv", 32 | "time" : { 33 | "start" : 1546843126673, 34 | "stop" : 1546843137417, 35 | "duration" : 10744 36 | }, 37 | "status" : "passed", 38 | "steps" : [ ], 39 | "attachments" : [ ], 40 | "parameters" : [ ], 41 | "stepsCount" : 0, 42 | "attachmentsCount" : 0, 43 | "shouldDisplayMessage" : false, 44 | "hasContent" : false 45 | }, { 46 | "name" : "caserun", 47 | "time" : { 48 | "start" : 1546843137418, 49 | "stop" : 1546843137418, 50 | "duration" : 0 51 | }, 52 | "status" : "passed", 53 | "steps" : [ ], 54 | "attachments" : [ ], 55 | "parameters" : [ ], 56 | "stepsCount" : 0, 57 | "attachmentsCount" : 0, 58 | "shouldDisplayMessage" : false, 59 | "hasContent" : false 60 | }, { 61 | "name" : "suitinit", 62 | "time" : { 63 | "start" : 1546843137418, 64 | "stop" : 1546843137418, 65 | "duration" : 0 66 | }, 67 | "status" : "passed", 68 | "steps" : [ ], 69 | "attachments" : [ ], 70 | "parameters" : [ ], 71 | "stepsCount" : 0, 72 | "attachmentsCount" : 0, 73 | "shouldDisplayMessage" : false, 74 | "hasContent" : false 75 | } ], 76 | "testStage" : { 77 | "status" : "broken", 78 | "statusMessage" : "TypeError: 'WebElement' object does not support indexing", 79 | "statusTrace" : "self = , action = \n\n def test_case1(self,action):\n count=5\n action.click(p.特卖首页.发布)\n \n for index in range(count):\n action.click(p.特卖首页.发布_上传视频)\n> videoele=action.find_ele(vp.视频发布页.视频选择)[0]\nE TypeError: 'WebElement' object does not support indexing\n\ntests/test_vedio/test_videorelease.py:19: TypeError", 80 | "steps" : [ ], 81 | "attachments" : [ { 82 | "uid" : "e0c69be8f1448ca3", 83 | "name" : "log", 84 | "source" : "e0c69be8f1448ca3.txt", 85 | "type" : "text/plain", 86 | "size" : 1126 87 | }, { 88 | "uid" : "bed1b75cd7491c29", 89 | "name" : "stdout", 90 | "source" : "bed1b75cd7491c29.txt", 91 | "type" : "text/plain", 92 | "size" : 0 93 | }, { 94 | "uid" : "6c7820d70b256863", 95 | "name" : "stderr", 96 | "source" : "6c7820d70b256863.txt", 97 | "type" : "text/plain", 98 | "size" : 0 99 | } ], 100 | "parameters" : [ ], 101 | "stepsCount" : 0, 102 | "attachmentsCount" : 3, 103 | "shouldDisplayMessage" : true, 104 | "hasContent" : true 105 | }, 106 | "afterStages" : [ { 107 | "name" : "action::0", 108 | "time" : { 109 | "start" : 1546843149537, 110 | "stop" : 1546843149874, 111 | "duration" : 337 112 | }, 113 | "status" : "passed", 114 | "steps" : [ ], 115 | "attachments" : [ ], 116 | "parameters" : [ ], 117 | "stepsCount" : 0, 118 | "attachmentsCount" : 0, 119 | "shouldDisplayMessage" : false, 120 | "hasContent" : false 121 | }, { 122 | "name" : "caserun::0", 123 | "time" : { 124 | "start" : 1546843146619, 125 | "stop" : 1546843149534, 126 | "duration" : 2915 127 | }, 128 | "status" : "passed", 129 | "steps" : [ ], 130 | "attachments" : [ { 131 | "uid" : "aba9b39786212361", 132 | "name" : "用例结束前的截图_14:39:09_.png", 133 | "source" : "aba9b39786212361.png", 134 | "type" : "image/png", 135 | "size" : 1516215 136 | } ], 137 | "parameters" : [ ], 138 | "stepsCount" : 0, 139 | "attachmentsCount" : 1, 140 | "shouldDisplayMessage" : false, 141 | "hasContent" : true 142 | } ], 143 | "labels" : [ { 144 | "name" : "parentSuite", 145 | "value" : "tests.test_vedio" 146 | }, { 147 | "name" : "suite", 148 | "value" : "test_videorelease" 149 | }, { 150 | "name" : "subSuite", 151 | "value" : "Test_videorelease" 152 | }, { 153 | "name" : "host", 154 | "value" : "tangmaoheng-deMacBook-Air.local" 155 | }, { 156 | "name" : "thread", 157 | "value" : "15490-MainThread" 158 | }, { 159 | "name" : "framework", 160 | "value" : "pytest" 161 | }, { 162 | "name" : "language", 163 | "value" : "cpython3" 164 | }, { 165 | "name" : "package", 166 | "value" : "tests.test_vedio.test_videorelease" 167 | }, { 168 | "name" : "resultFormat", 169 | "value" : "allure2" 170 | } ], 171 | "parameters" : [ ], 172 | "links" : [ ], 173 | "hidden" : true, 174 | "retry" : true, 175 | "extra" : { 176 | "categories" : [ ], 177 | "tags" : [ ] 178 | }, 179 | "source" : "2badf96700036808.json", 180 | "parameterValues" : [ ] 181 | } -------------------------------------------------------------------------------- /report/html/data/test-cases/86e14bf2f8865824.json: -------------------------------------------------------------------------------- 1 | { 2 | "uid" : "86e14bf2f8865824", 3 | "name" : "test_case1", 4 | "fullName" : "tests.test_vedio.test_videorelease.Test_videorelease#test_case1", 5 | "historyId" : "61d0ec5868142760393bb75a0ddaae70", 6 | "time" : { }, 7 | "status" : "broken", 8 | "statusMessage" : "UnboundLocalError: local variable 'Resolution' referenced before assignment", 9 | "statusTrace" : "> lambda: ihook(item=item, **kwds),\n when=when,\n )\n\n/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/flaky/flaky_pytest_plugin.py:273: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\nbase/conftest_android.py:58: in action\n element_action=ElementActions(driverenv)\nbase/utils.py:15: in getinstance\n instances[class_] = class_(*args, **kwargs)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\nself = , driver = \n\n def __init__(self, driver: webdriver.Remote):\n self.driver = driver\n self.env = EnvironmentAndroid()\n #通过driver.get_window_size()获取的分辨率会不准确,所以读取配置的Resolution\n self.Resolution =self.env.current_device.get('Resolution')\n \n> if Resolution==None:\nE UnboundLocalError: local variable 'Resolution' referenced before assignment\n\nbase/action.py:27: UnboundLocalError", 10 | "flaky" : false, 11 | "beforeStages" : [ { 12 | "name" : "driverenv", 13 | "time" : { 14 | "start" : 1546833831871, 15 | "stop" : 1546833843506, 16 | "duration" : 11635 17 | }, 18 | "status" : "passed", 19 | "steps" : [ ], 20 | "attachments" : [ ], 21 | "parameters" : [ ], 22 | "stepsCount" : 0, 23 | "attachmentsCount" : 0, 24 | "shouldDisplayMessage" : false, 25 | "hasContent" : false 26 | }, { 27 | "name" : "action", 28 | "time" : { 29 | "start" : 1546833843507, 30 | "stop" : 1546833843507, 31 | "duration" : 0 32 | }, 33 | "status" : "broken", 34 | "statusMessage" : "UnboundLocalError: local variable 'Resolution' referenced before assignment\n", 35 | "statusTrace" : " File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pluggy/callers.py\", line 187, in _multicall\n res = hook_impl.function(*args)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 969, in pytest_fixture_setup\n result = call_fixture_func(fixturefunc, request, kwargs)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 824, in call_fixture_func\n res = next(it)\n File \"/Users/tmh/PycharmProjects/appauto/base/conftest_android.py\", line 58, in action\n element_action=ElementActions(driverenv)\n File \"/Users/tmh/PycharmProjects/appauto/base/utils.py\", line 15, in getinstance\n instances[class_] = class_(*args, **kwargs)\n File \"/Users/tmh/PycharmProjects/appauto/base/action.py\", line 27, in __init__\n if Resolution==None:\n", 36 | "steps" : [ ], 37 | "attachments" : [ ], 38 | "parameters" : [ ], 39 | "stepsCount" : 0, 40 | "attachmentsCount" : 0, 41 | "shouldDisplayMessage" : true, 42 | "hasContent" : true 43 | } ], 44 | "testStage" : { 45 | "status" : "broken", 46 | "statusMessage" : "UnboundLocalError: local variable 'Resolution' referenced before assignment", 47 | "statusTrace" : "> lambda: ihook(item=item, **kwds),\n when=when,\n )\n\n/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/flaky/flaky_pytest_plugin.py:273: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\nbase/conftest_android.py:58: in action\n element_action=ElementActions(driverenv)\nbase/utils.py:15: in getinstance\n instances[class_] = class_(*args, **kwargs)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\nself = , driver = \n\n def __init__(self, driver: webdriver.Remote):\n self.driver = driver\n self.env = EnvironmentAndroid()\n #通过driver.get_window_size()获取的分辨率会不准确,所以读取配置的Resolution\n self.Resolution =self.env.current_device.get('Resolution')\n \n> if Resolution==None:\nE UnboundLocalError: local variable 'Resolution' referenced before assignment\n\nbase/action.py:27: UnboundLocalError", 48 | "steps" : [ ], 49 | "attachments" : [ { 50 | "uid" : "ab94871d11b3a4c2", 51 | "name" : "log", 52 | "source" : "ab94871d11b3a4c2.txt", 53 | "type" : "text/plain", 54 | "size" : 546 55 | }, { 56 | "uid" : "e3ce77b42d6a67bc", 57 | "name" : "stdout", 58 | "source" : "e3ce77b42d6a67bc.txt", 59 | "type" : "text/plain", 60 | "size" : 0 61 | }, { 62 | "uid" : "b449cc3f836fe944", 63 | "name" : "stderr", 64 | "source" : "b449cc3f836fe944.txt", 65 | "type" : "text/plain", 66 | "size" : 0 67 | } ], 68 | "parameters" : [ ], 69 | "stepsCount" : 0, 70 | "attachmentsCount" : 3, 71 | "shouldDisplayMessage" : true, 72 | "hasContent" : true 73 | }, 74 | "afterStages" : [ ], 75 | "labels" : [ { 76 | "name" : "parentSuite", 77 | "value" : "tests.test_vedio" 78 | }, { 79 | "name" : "suite", 80 | "value" : "test_videorelease" 81 | }, { 82 | "name" : "subSuite", 83 | "value" : "Test_videorelease" 84 | }, { 85 | "name" : "host", 86 | "value" : "tangmaoheng-deMacBook-Air.local" 87 | }, { 88 | "name" : "thread", 89 | "value" : "14497-MainThread" 90 | }, { 91 | "name" : "framework", 92 | "value" : "pytest" 93 | }, { 94 | "name" : "language", 95 | "value" : "cpython3" 96 | }, { 97 | "name" : "package", 98 | "value" : "tests.test_vedio.test_videorelease" 99 | }, { 100 | "name" : "resultFormat", 101 | "value" : "allure2" 102 | } ], 103 | "parameters" : [ ], 104 | "links" : [ ], 105 | "hidden" : true, 106 | "retry" : true, 107 | "extra" : { 108 | "categories" : [ ], 109 | "tags" : [ ] 110 | }, 111 | "source" : "86e14bf2f8865824.json", 112 | "parameterValues" : [ ] 113 | } -------------------------------------------------------------------------------- /report/html/data/test-cases/b21acd4f81e0178b.json: -------------------------------------------------------------------------------- 1 | { 2 | "uid" : "b21acd4f81e0178b", 3 | "name" : "test_case1", 4 | "fullName" : "tests.test_vedio.test_videorelease.Test_videorelease#test_case1", 5 | "historyId" : "61d0ec5868142760393bb75a0ddaae70", 6 | "time" : { 7 | "start" : 1546843185735, 8 | "stop" : 1546843342535, 9 | "duration" : 156800 10 | }, 11 | "status" : "passed", 12 | "flaky" : true, 13 | "beforeStages" : [ { 14 | "name" : "driverenv", 15 | "time" : { 16 | "start" : 1546843175425, 17 | "stop" : 1546843185733, 18 | "duration" : 10308 19 | }, 20 | "status" : "passed", 21 | "steps" : [ ], 22 | "attachments" : [ ], 23 | "parameters" : [ ], 24 | "stepsCount" : 0, 25 | "attachmentsCount" : 0, 26 | "shouldDisplayMessage" : false, 27 | "hasContent" : false 28 | }, { 29 | "name" : "action", 30 | "time" : { 31 | "start" : 1546843185733, 32 | "stop" : 1546843185733, 33 | "duration" : 0 34 | }, 35 | "status" : "passed", 36 | "steps" : [ ], 37 | "attachments" : [ ], 38 | "parameters" : [ ], 39 | "stepsCount" : 0, 40 | "attachmentsCount" : 0, 41 | "shouldDisplayMessage" : false, 42 | "hasContent" : false 43 | }, { 44 | "name" : "caserun", 45 | "time" : { 46 | "start" : 1546843185733, 47 | "stop" : 1546843185734, 48 | "duration" : 1 49 | }, 50 | "status" : "passed", 51 | "steps" : [ ], 52 | "attachments" : [ ], 53 | "parameters" : [ ], 54 | "stepsCount" : 0, 55 | "attachmentsCount" : 0, 56 | "shouldDisplayMessage" : false, 57 | "hasContent" : false 58 | }, { 59 | "name" : "suitinit", 60 | "time" : { 61 | "start" : 1546843185733, 62 | "stop" : 1546843185733, 63 | "duration" : 0 64 | }, 65 | "status" : "passed", 66 | "steps" : [ ], 67 | "attachments" : [ ], 68 | "parameters" : [ ], 69 | "stepsCount" : 0, 70 | "attachmentsCount" : 0, 71 | "shouldDisplayMessage" : false, 72 | "hasContent" : false 73 | } ], 74 | "testStage" : { 75 | "status" : "passed", 76 | "steps" : [ ], 77 | "attachments" : [ { 78 | "uid" : "bc1be12f7bde1a6", 79 | "name" : "上传后截图_14:40:26_.png", 80 | "source" : "bc1be12f7bde1a6.png", 81 | "type" : "image/png", 82 | "size" : 1031954 83 | }, { 84 | "uid" : "5337e0bfb50b06c0", 85 | "name" : "上传后截图_14:40:53_.png", 86 | "source" : "5337e0bfb50b06c0.png", 87 | "type" : "image/png", 88 | "size" : 1028539 89 | }, { 90 | "uid" : "69de7f3952a72a0d", 91 | "name" : "上传后截图_14:41:21_.png", 92 | "source" : "69de7f3952a72a0d.png", 93 | "type" : "image/png", 94 | "size" : 1013554 95 | }, { 96 | "uid" : "364443a71485466e", 97 | "name" : "上传后截图_14:41:50_.png", 98 | "source" : "364443a71485466e.png", 99 | "type" : "image/png", 100 | "size" : 899482 101 | }, { 102 | "uid" : "6404365aaa5f191a", 103 | "name" : "上传后截图_14:42:22_.png", 104 | "source" : "6404365aaa5f191a.png", 105 | "type" : "image/png", 106 | "size" : 980627 107 | }, { 108 | "uid" : "c354537fab992c28", 109 | "name" : "log", 110 | "source" : "c354537fab992c28.txt", 111 | "type" : "text/plain", 112 | "size" : 4573 113 | }, { 114 | "uid" : "d292a7adda173007", 115 | "name" : "stdout", 116 | "source" : "d292a7adda173007.txt", 117 | "type" : "text/plain", 118 | "size" : 0 119 | }, { 120 | "uid" : "184e4b9f713ed749", 121 | "name" : "stderr", 122 | "source" : "184e4b9f713ed749.txt", 123 | "type" : "text/plain", 124 | "size" : 0 125 | } ], 126 | "parameters" : [ ], 127 | "stepsCount" : 0, 128 | "attachmentsCount" : 8, 129 | "shouldDisplayMessage" : false, 130 | "hasContent" : true 131 | }, 132 | "afterStages" : [ { 133 | "name" : "action::0", 134 | "time" : { 135 | "start" : 1546843344195, 136 | "stop" : 1546843344440, 137 | "duration" : 245 138 | }, 139 | "status" : "passed", 140 | "steps" : [ ], 141 | "attachments" : [ ], 142 | "parameters" : [ ], 143 | "stepsCount" : 0, 144 | "attachmentsCount" : 0, 145 | "shouldDisplayMessage" : false, 146 | "hasContent" : false 147 | }, { 148 | "name" : "caserun::0", 149 | "time" : { 150 | "start" : 1546843342536, 151 | "stop" : 1546843344193, 152 | "duration" : 1657 153 | }, 154 | "status" : "passed", 155 | "steps" : [ ], 156 | "attachments" : [ { 157 | "uid" : "a007d84425b5bb63", 158 | "name" : "用例结束前的截图_14:42:24_.png", 159 | "source" : "a007d84425b5bb63.png", 160 | "type" : "image/png", 161 | "size" : 284897 162 | } ], 163 | "parameters" : [ ], 164 | "stepsCount" : 0, 165 | "attachmentsCount" : 1, 166 | "shouldDisplayMessage" : false, 167 | "hasContent" : true 168 | } ], 169 | "labels" : [ { 170 | "name" : "parentSuite", 171 | "value" : "tests.test_vedio" 172 | }, { 173 | "name" : "suite", 174 | "value" : "test_videorelease" 175 | }, { 176 | "name" : "subSuite", 177 | "value" : "Test_videorelease" 178 | }, { 179 | "name" : "host", 180 | "value" : "tangmaoheng-deMacBook-Air.local" 181 | }, { 182 | "name" : "thread", 183 | "value" : "15614-MainThread" 184 | }, { 185 | "name" : "framework", 186 | "value" : "pytest" 187 | }, { 188 | "name" : "language", 189 | "value" : "cpython3" 190 | }, { 191 | "name" : "package", 192 | "value" : "tests.test_vedio.test_videorelease" 193 | }, { 194 | "name" : "resultFormat", 195 | "value" : "allure2" 196 | } ], 197 | "parameters" : [ ], 198 | "links" : [ ], 199 | "hidden" : false, 200 | "retry" : false, 201 | "extra" : { 202 | "severity" : "normal", 203 | "retries" : [ { 204 | "uid" : "2badf96700036808", 205 | "status" : "broken", 206 | "statusDetails" : "TypeError: 'WebElement' object does not support indexing", 207 | "time" : { 208 | "start" : 1546843137419, 209 | "stop" : 1546843146535, 210 | "duration" : 9116 211 | } 212 | }, { 213 | "uid" : "24f58f1ec11332d9", 214 | "status" : "broken", 215 | "statusDetails" : "base.verify.NotFoundElementError", 216 | "time" : { 217 | "start" : 1546843021518, 218 | "stop" : 1546843036235, 219 | "duration" : 14717 220 | } 221 | }, { 222 | "uid" : "f0ae3bd5a8ce2bb", 223 | "status" : "broken", 224 | "statusDetails" : "base.verify.NotFoundElementError", 225 | "time" : { 226 | "start" : 1546842463044, 227 | "stop" : 1546842470808, 228 | "duration" : 7764 229 | } 230 | }, { 231 | "uid" : "cc5b3686faaafc7d", 232 | "status" : "broken", 233 | "statusDetails" : "base.verify.NotFoundElementError", 234 | "time" : { 235 | "start" : 1546833967879, 236 | "stop" : 1546833975071, 237 | "duration" : 7192 238 | } 239 | }, { 240 | "uid" : "86e14bf2f8865824", 241 | "status" : "broken", 242 | "statusDetails" : "UnboundLocalError: local variable 'Resolution' referenced before assignment", 243 | "time" : { } 244 | }, { 245 | "uid" : "1c34a555846b7834", 246 | "status" : "broken", 247 | "statusDetails" : "TypeError: 'NoneType' object is not subscriptable", 248 | "time" : { } 249 | }, { 250 | "uid" : "5e5ab8d7f354b64e", 251 | "status" : "broken", 252 | "statusDetails" : "selenium.common.exceptions.InvalidArgumentException: Message: 'unicodeKeyboard' must be of type boolean", 253 | "time" : { } 254 | }, { 255 | "uid" : "ec79099cdc5058fa", 256 | "status" : "broken", 257 | "statusDetails" : "selenium.common.exceptions.InvalidArgumentException: Message: 'unicodeKeyboard' must be of type boolean", 258 | "time" : { } 259 | }, { 260 | "uid" : "5c92766a12bb5ee2", 261 | "status" : "broken", 262 | "statusDetails" : "selenium.common.exceptions.InvalidArgumentException: Message: 'unicodeKeyboard' must be of type boolean", 263 | "time" : { } 264 | }, { 265 | "uid" : "368f23af01311881", 266 | "status" : "broken", 267 | "statusDetails" : "selenium.common.exceptions.InvalidArgumentException: Message: 'unicodeKeyboard' must be of type boolean", 268 | "time" : { } 269 | } ], 270 | "categories" : [ ], 271 | "tags" : [ ] 272 | }, 273 | "source" : "b21acd4f81e0178b.json", 274 | "parameterValues" : [ ] 275 | } -------------------------------------------------------------------------------- /report/html/data/timeline.json: -------------------------------------------------------------------------------- 1 | { 2 | "uid" : "ab17fc5a4eb3bca4b216b548c7f9fcbc", 3 | "name" : "timeline", 4 | "children" : [ { 5 | "name" : "tangmaoheng-deMacBook-Air.local", 6 | "children" : [ { 7 | "name" : "15614-MainThread", 8 | "children" : [ { 9 | "name" : "test_case1", 10 | "uid" : "b21acd4f81e0178b", 11 | "parentUid" : "48c89c5e2b49cd547b6250d5ea6fdca2", 12 | "status" : "passed", 13 | "time" : { 14 | "start" : 1546843185735, 15 | "stop" : 1546843342535, 16 | "duration" : 156800 17 | }, 18 | "flaky" : true, 19 | "parameters" : [ ] 20 | } ], 21 | "uid" : "48c89c5e2b49cd547b6250d5ea6fdca2" 22 | } ], 23 | "uid" : "577e26d22381ed8ab20093e9d6c8c9bf" 24 | } ] 25 | } -------------------------------------------------------------------------------- /report/html/export/influxDbData.txt: -------------------------------------------------------------------------------- 1 | launch_status failed=0 1546843347000000000 2 | launch_status broken=0 1546843347000000000 3 | launch_status passed=1 1546843347000000000 4 | launch_status skipped=0 1546843347000000000 5 | launch_status unknown=0 1546843347000000000 6 | launch_time duration=156800 1546843347000000000 7 | launch_time min_duration=156800 1546843347000000000 8 | launch_time max_duration=156800 1546843347000000000 9 | launch_time sum_duration=156800 1546843347000000000 10 | launch_retries retries=10 1546843347000000000 11 | launch_retries run=1 1546843347000000000 12 | -------------------------------------------------------------------------------- /report/html/export/mail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Allure Report summary mail 6 | 7 | 8 | Mail body 9 | 10 | 11 | -------------------------------------------------------------------------------- /report/html/export/prometheusData.txt: -------------------------------------------------------------------------------- 1 | launch_status_failed 0 2 | launch_status_broken 0 3 | launch_status_passed 1 4 | launch_status_skipped 0 5 | launch_status_unknown 0 6 | launch_time_duration 156800 7 | launch_time_min_duration 156800 8 | launch_time_max_duration 156800 9 | launch_time_sum_duration 156800 10 | launch_retries_retries 10 11 | launch_retries_run 1 12 | -------------------------------------------------------------------------------- /report/html/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/html/favicon.ico -------------------------------------------------------------------------------- /report/html/history/categories-trend.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "data" : { } 3 | } ] -------------------------------------------------------------------------------- /report/html/history/duration-trend.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "data" : { 3 | "duration" : 156800 4 | } 5 | } ] -------------------------------------------------------------------------------- /report/html/history/history-trend.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "data" : { 3 | "failed" : 0, 4 | "broken" : 0, 5 | "skipped" : 0, 6 | "passed" : 1, 7 | "unknown" : 0, 8 | "total" : 1 9 | } 10 | } ] -------------------------------------------------------------------------------- /report/html/history/history.json: -------------------------------------------------------------------------------- 1 | { 2 | "61d0ec5868142760393bb75a0ddaae70" : { 3 | "statistic" : { 4 | "failed" : 0, 5 | "broken" : 0, 6 | "skipped" : 0, 7 | "passed" : 1, 8 | "unknown" : 0, 9 | "total" : 1 10 | }, 11 | "items" : [ { 12 | "uid" : "b21acd4f81e0178b", 13 | "status" : "passed", 14 | "time" : { 15 | "start" : 1546843185735, 16 | "stop" : 1546843342535, 17 | "duration" : 156800 18 | } 19 | } ] 20 | } 21 | } -------------------------------------------------------------------------------- /report/html/history/retry-trend.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "data" : { 3 | "run" : 1, 4 | "retry" : 10 5 | } 6 | } ] -------------------------------------------------------------------------------- /report/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Allure Report 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /report/html/plugins/behaviors/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | allure.api.addTranslation('en', { 4 | tab: { 5 | behaviors: { 6 | name: 'Behaviors' 7 | } 8 | }, 9 | widget: { 10 | behaviors: { 11 | name: 'Features by stories', 12 | showAll: 'show all' 13 | } 14 | } 15 | }); 16 | 17 | allure.api.addTranslation('ru', { 18 | tab: { 19 | behaviors: { 20 | name: 'Функциональность' 21 | } 22 | }, 23 | widget: { 24 | behaviors: { 25 | name: 'Функциональность', 26 | showAll: 'показать все' 27 | } 28 | } 29 | }); 30 | 31 | allure.api.addTranslation('zh', { 32 | tab: { 33 | behaviors: { 34 | name: '功能' 35 | } 36 | }, 37 | widget: { 38 | behaviors: { 39 | name: '特性场景', 40 | showAll: '显示所有' 41 | } 42 | } 43 | }); 44 | 45 | allure.api.addTranslation('de', { 46 | tab: { 47 | behaviors: { 48 | name: 'Verhalten' 49 | } 50 | }, 51 | widget: { 52 | behaviors: { 53 | name: 'Features nach Stories', 54 | showAll: 'Zeige alle' 55 | } 56 | } 57 | }); 58 | 59 | allure.api.addTranslation('he', { 60 | tab: { 61 | behaviors: { 62 | name: 'התנהגויות' 63 | } 64 | }, 65 | widget: { 66 | behaviors: { 67 | name: 'תכונות לפי סיפורי משתמש', 68 | showAll: 'הצג הכול' 69 | } 70 | } 71 | }); 72 | 73 | allure.api.addTranslation('br', { 74 | tab: { 75 | behaviors: { 76 | name: 'Comportamentos' 77 | } 78 | }, 79 | widget: { 80 | behaviors: { 81 | name: 'Funcionalidades por história', 82 | showAll: 'Mostrar tudo' 83 | } 84 | } 85 | }); 86 | 87 | allure.api.addTab('behaviors', { 88 | title: 'tab.behaviors.name', icon: 'fa fa-list', 89 | route: 'behaviors(/)(:testGroup)(/)(:testResult)(/)(:testResultTab)(/)', 90 | onEnter: (function (testGroup, testResult, testResultTab) { 91 | return new allure.components.TreeLayout({ 92 | testGroup: testGroup, 93 | testResult: testResult, 94 | testResultTab: testResultTab, 95 | tabName: 'tab.behaviors.name', 96 | baseUrl: 'behaviors', 97 | url: 'data/behaviors.json', 98 | csvUrl: 'data/behaviors.csv' 99 | }); 100 | }) 101 | }); 102 | 103 | allure.api.addWidget('widgets', 'behaviors', allure.components.WidgetStatusView.extend({ 104 | rowTag: 'a', 105 | title: 'widget.behaviors.name', 106 | baseUrl: 'behaviors', 107 | showLinks: true 108 | })); -------------------------------------------------------------------------------- /report/html/plugins/packages/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | allure.api.addTranslation('en', { 4 | tab: { 5 | packages: { 6 | name: 'Packages' 7 | } 8 | } 9 | }); 10 | 11 | allure.api.addTranslation('ru', { 12 | tab: { 13 | packages: { 14 | name: 'Пакеты' 15 | } 16 | } 17 | }); 18 | 19 | allure.api.addTranslation('zh', { 20 | tab: { 21 | packages: { 22 | name: '包' 23 | } 24 | } 25 | }); 26 | 27 | allure.api.addTranslation('de', { 28 | tab: { 29 | packages: { 30 | name: 'Pakete' 31 | } 32 | } 33 | }); 34 | 35 | allure.api.addTranslation('he', { 36 | tab: { 37 | packages: { 38 | name: 'חבילות' 39 | } 40 | } 41 | }); 42 | 43 | allure.api.addTranslation('br', { 44 | tab: { 45 | packages: { 46 | name: 'Pacotes' 47 | } 48 | } 49 | }); 50 | 51 | allure.api.addTab('packages', { 52 | title: 'tab.packages.name', icon: 'fa fa-align-left', 53 | route: 'packages(/)(:testGroup)(/)(:testResult)(/)(:testResultTab)(/)', 54 | onEnter: (function (testGroup, testResult, testResultTab) { 55 | return new allure.components.TreeLayout({ 56 | testGroup: testGroup, 57 | testResult: testResult, 58 | testResultTab: testResultTab, 59 | tabName: 'tab.packages.name', 60 | baseUrl: 'packages', 61 | url: 'data/packages.json' 62 | }); 63 | }) 64 | }); 65 | -------------------------------------------------------------------------------- /report/html/plugins/screen-diff/index.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var settings = allure.getPluginSettings('screen-diff', {diffType: 'diff'}); 3 | 4 | function renderImage(src) { 5 | return '
' + 6 | '' + 7 | '
'; 8 | } 9 | 10 | function renderDiffContent(type, data) { 11 | function findImage(name) { 12 | if (data.testStage && data.testStage.attachments) { 13 | return data.testStage.attachments.filter(function (attachment) { 14 | return attachment.name === name; 15 | })[0]; 16 | } 17 | return null; 18 | } 19 | 20 | var diffImage = findImage('diff'); 21 | var actualImage = findImage('actual'); 22 | var expectedImage = findImage('expected'); 23 | 24 | if (!diffImage && !actualImage && !expectedImage) { 25 | return 'Diff, actual and expected image have not been provided.'; 26 | } 27 | 28 | if (type === 'diff') { 29 | if (!diffImage) { 30 | return renderImage(actualImage.source); 31 | } 32 | return renderImage(diffImage.source); 33 | } 34 | if (type === 'overlay') { 35 | return '
' + 36 | '' + 37 | '
' + 38 | '' + 39 | '
' + 40 | '
'; 41 | } 42 | } 43 | 44 | var ScreenDiffView = Backbone.Marionette.View.extend({ 45 | className: 'pane__section', 46 | events: { 47 | 'click [name="screen-diff-type"]': 'onDiffTypeChange', 48 | 'mousemove .screen-diff__overlay': 'onOverlayMove' 49 | }, 50 | templateContext: function () { 51 | return { 52 | diffType: settings.get('diffType') 53 | } 54 | }, 55 | template: function (data) { 56 | var testType = data.labels.filter(function (label) { 57 | return label.name === 'testType' 58 | })[0]; 59 | 60 | if (!testType || testType.value !== 'screenshotDiff') { 61 | return ''; 62 | } 63 | 64 | return '

Screen Diff

' + 65 | '
' + 66 | '
' + 67 | '' + 68 | '' + 69 | '
' + 70 | renderDiffContent(data.diffType, data) + 71 | '
'; 72 | }, 73 | adjustImageSize: function (event) { 74 | var overImage = this.$(event.target); 75 | overImage.width(overImage.width()); 76 | }, 77 | onRender: function () { 78 | const diffType = settings.get('diffType'); 79 | this.$('[name="screen-diff-type"][value="' + diffType + '"]').prop('checked', true); 80 | if (diffType === 'overlay') { 81 | this.$('.screen-diff__image-over img').on('load', this.adjustImageSize.bind(this)); 82 | } 83 | }, 84 | onOverlayMove: function (event) { 85 | var pageX = event.pageX; 86 | var containerScroll = this.$('.screen-diff__container').scrollLeft(); 87 | var elementX = event.currentTarget.getBoundingClientRect().left; 88 | var delta = pageX - elementX + containerScroll; 89 | this.$('.screen-diff__image-over').width(delta); 90 | }, 91 | onDiffTypeChange: function (event) { 92 | settings.save('diffType', event.target.value); 93 | this.render(); 94 | } 95 | }); 96 | allure.api.addTestResultBlock(ScreenDiffView, {position: 'before'}); 97 | })(); 98 | -------------------------------------------------------------------------------- /report/html/plugins/screen-diff/styles.css: -------------------------------------------------------------------------------- 1 | .screen-diff__switchers { 2 | margin-bottom: 1em; 3 | } 4 | 5 | .screen-diff__switchers label + label { 6 | margin-left: 1em; 7 | } 8 | 9 | .screen-diff__overlay { 10 | position: relative; 11 | cursor: col-resize; 12 | } 13 | 14 | .screen-diff__container { 15 | overflow-x: auto; 16 | } 17 | 18 | .screen-diff__image-over { 19 | top: 0; 20 | left: 0; 21 | bottom: 0; 22 | background: #fff; 23 | position: absolute; 24 | overflow: hidden; 25 | box-shadow: 2px 0 1px -1px #aaa; 26 | } 27 | -------------------------------------------------------------------------------- /report/html/widgets/behaviors.json: -------------------------------------------------------------------------------- 1 | { 2 | "total" : 1, 3 | "items" : [ ] 4 | } -------------------------------------------------------------------------------- /report/html/widgets/categories-trend.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "data" : { } 3 | } ] -------------------------------------------------------------------------------- /report/html/widgets/categories.json: -------------------------------------------------------------------------------- 1 | { 2 | "total" : 0, 3 | "items" : [ ] 4 | } -------------------------------------------------------------------------------- /report/html/widgets/duration-trend.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "data" : { 3 | "duration" : 156800 4 | } 5 | } ] -------------------------------------------------------------------------------- /report/html/widgets/duration.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "uid" : "b21acd4f81e0178b", 3 | "name" : "test_case1", 4 | "time" : { 5 | "start" : 1546843185735, 6 | "stop" : 1546843342535, 7 | "duration" : 156800 8 | }, 9 | "status" : "passed", 10 | "severity" : "normal" 11 | } ] -------------------------------------------------------------------------------- /report/html/widgets/environment.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "values" : [ "8.1.0" ], 3 | "name" : "device1.platformVersion" 4 | }, { 5 | "values" : [ "/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk" ], 6 | "name" : "appium.app" 7 | }, { 8 | "values" : [ "http://localhost:4723/wd/hub" ], 9 | "name" : "device1.appiumserver" 10 | }, { 11 | "values" : [ "http://localhost:4723/wd/hub" ], 12 | "name" : "appium.host" 13 | }, { 14 | "values" : [ "/Users/tmh/PycharmProjects/appauto/report" ], 15 | "name" : "path.report" 16 | }, { 17 | "values" : [ "com.jm.android.jumei" ], 18 | "name" : "appium.appPackage" 19 | }, { 20 | "values" : [ "Android" ], 21 | "name" : "device1.platformName" 22 | }, { 23 | "values" : [ "android" ], 24 | "name" : "platform.run" 25 | }, { 26 | "values" : [ "com.jm.android.jumei.home.activity.StartActivity" ], 27 | "name" : "appium.appActivity" 28 | }, { 29 | "values" : [ "8201" ], 30 | "name" : "device1.systemPort" 31 | }, { 32 | "values" : [ "/Users/tmh/PycharmProjects/appauto/tests" ], 33 | "name" : "path.tests" 34 | }, { 35 | "values" : [ "1.9.1" ], 36 | "name" : "appium.version" 37 | }, { 38 | "values" : [ "2425a80b" ], 39 | "name" : "device1.deviceName" 40 | } ] -------------------------------------------------------------------------------- /report/html/widgets/executors.json: -------------------------------------------------------------------------------- 1 | [ ] -------------------------------------------------------------------------------- /report/html/widgets/history-trend.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "data" : { 3 | "failed" : 0, 4 | "broken" : 0, 5 | "skipped" : 0, 6 | "passed" : 1, 7 | "unknown" : 0, 8 | "total" : 1 9 | } 10 | } ] -------------------------------------------------------------------------------- /report/html/widgets/launch.json: -------------------------------------------------------------------------------- 1 | [ ] -------------------------------------------------------------------------------- /report/html/widgets/retry-trend.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "data" : { 3 | "run" : 1, 4 | "retry" : 10 5 | } 6 | } ] -------------------------------------------------------------------------------- /report/html/widgets/severity.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "uid" : "b21acd4f81e0178b", 3 | "name" : "test_case1", 4 | "time" : { 5 | "start" : 1546843185735, 6 | "stop" : 1546843342535, 7 | "duration" : 156800 8 | }, 9 | "status" : "passed", 10 | "severity" : "normal" 11 | } ] -------------------------------------------------------------------------------- /report/html/widgets/status-chart.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "uid" : "b21acd4f81e0178b", 3 | "name" : "test_case1", 4 | "time" : { 5 | "start" : 1546843185735, 6 | "stop" : 1546843342535, 7 | "duration" : 156800 8 | }, 9 | "status" : "passed", 10 | "severity" : "normal" 11 | } ] -------------------------------------------------------------------------------- /report/html/widgets/suites.json: -------------------------------------------------------------------------------- 1 | { 2 | "total" : 1, 3 | "items" : [ { 4 | "uid" : "c1f82c4d30338d8578cbc977fea9ed65", 5 | "name" : "tests.test_vedio", 6 | "statistic" : { 7 | "failed" : 0, 8 | "broken" : 0, 9 | "skipped" : 0, 10 | "passed" : 1, 11 | "unknown" : 0, 12 | "total" : 1 13 | } 14 | } ] 15 | } -------------------------------------------------------------------------------- /report/html/widgets/summary.json: -------------------------------------------------------------------------------- 1 | { 2 | "reportName" : "Allure Report", 3 | "testRuns" : [ ], 4 | "statistic" : { 5 | "failed" : 0, 6 | "broken" : 0, 7 | "skipped" : 0, 8 | "passed" : 1, 9 | "unknown" : 0, 10 | "total" : 1 11 | }, 12 | "time" : { 13 | "start" : 1546843185735, 14 | "stop" : 1546843342535, 15 | "duration" : 156800, 16 | "minDuration" : 156800, 17 | "maxDuration" : 156800, 18 | "sumDuration" : 156800 19 | } 20 | } -------------------------------------------------------------------------------- /report/xml/0ac8a7b4-ca14-4f30-8048-929374fc143d-attachment.txt: -------------------------------------------------------------------------------- 1 | INFO 14:38:46 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': True, 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} 2 | 3 | INFO 14:38:57 ————————————————————————执行用例 ----------—————————————— 4 | INFO 14:38:57 [点击] 页面【特卖首页】的元素【发布】 5 | 6 | INFO 14:39:02 [点击] 页面【特卖首页】的元素【上传视频】 7 | 8 | INFO 14:39:05 查找 页面【视频发布页】的元素【视频选择】 9 | INFO 14:39:06 sleep等待 1 s 10 | 11 | INFO 14:39:09 ————————————————————————该用例执行结束 ----------—————————————— -------------------------------------------------------------------------------- /report/xml/0b80182a-5c2d-44fd-926e-b8970e982495-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/0b80182a-5c2d-44fd-926e-b8970e982495-attachment.txt -------------------------------------------------------------------------------- /report/xml/0d40c3e0-f16c-4f30-9208-348a2d7134ae-attachment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/0d40c3e0-f16c-4f30-9208-348a2d7134ae-attachment.png -------------------------------------------------------------------------------- /report/xml/0f133a6f-8510-4798-98f3-2c49a8034ad3-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "69ac5925-d146-4677-b66d-1416274d8295", "children": ["a1903318-27e1-451d-a652-4b1b792b37c2"], "befores": [{"name": "suitinit", "status": "passed", "start": 1546833935129, "stop": 1546833967877}], "start": 1546833935129, "stop": 1546833976985} -------------------------------------------------------------------------------- /report/xml/135030ec-ef31-4ac4-8d16-25db85813b8f-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/135030ec-ef31-4ac4-8d16-25db85813b8f-attachment.txt -------------------------------------------------------------------------------- /report/xml/16486324-2ffb-443c-bc74-df4be503793e-result.json: -------------------------------------------------------------------------------- 1 | {"name": "test_case1", "status": "broken", "statusDetails": {"message": "selenium.common.exceptions.InvalidArgumentException: Message: 'unicodeKeyboard' must be of type boolean", "trace": "> lambda: ihook(item=item, **kwds),\n when=when,\n )\n\n/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/flaky/flaky_pytest_plugin.py:273: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\nbase/conftest_android.py:50: in driverenv\n driver = webdriver.Remote(host, capabilities)\n/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/appium/webdriver/webdriver.py:97: in __init__\n super(WebDriver, self).__init__(command_executor, desired_capabilities, browser_profile, proxy, keep_alive)\n/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py:157: in __init__\n self.start_session(capabilities, browser_profile)\n/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/appium/webdriver/webdriver.py:138: in start_session\n response = self.execute(RemoteCommand.NEW_SESSION, parameters)\n/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py:321: in execute\n self.error_handler.check_response(response)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\nself = \nresponse = {'status': 400, 'value': '{\"value\":{\"error\":\"invalid argument\",\"message\":\"\\'unicodeKeyboard\\' must be of type boolean\".../app/node_modules/appium/lib/appium.js:292:43)\\\\n at process._tickCallback (internal/process/next_tick.js:68:7)\"}}'}\n\n def check_response(self, response):\n \"\"\"\n Checks that a JSON response from the WebDriver does not have an error.\n \n :Args:\n - response - The JSON response from the WebDriver server as a dictionary\n object.\n \n :Raises: If the response contains an error message.\n \"\"\"\n status = response.get('status', None)\n if status is None or status == ErrorCode.SUCCESS:\n return\n value = None\n message = response.get(\"message\", \"\")\n screen = response.get(\"screen\", \"\")\n stacktrace = None\n if isinstance(status, int):\n value_json = response.get('value', None)\n if value_json and isinstance(value_json, basestring):\n import json\n try:\n value = json.loads(value_json)\n if len(value.keys()) == 1:\n value = value['value']\n status = value.get('error', None)\n if status is None:\n status = value[\"status\"]\n message = value[\"value\"]\n if not isinstance(message, basestring):\n value = message\n message = message.get('message')\n else:\n message = value.get('message', None)\n except ValueError:\n pass\n \n exception_class = ErrorInResponseException\n if status in ErrorCode.NO_SUCH_ELEMENT:\n exception_class = NoSuchElementException\n elif status in ErrorCode.NO_SUCH_FRAME:\n exception_class = NoSuchFrameException\n elif status in ErrorCode.NO_SUCH_WINDOW:\n exception_class = NoSuchWindowException\n elif status in ErrorCode.STALE_ELEMENT_REFERENCE:\n exception_class = StaleElementReferenceException\n elif status in ErrorCode.ELEMENT_NOT_VISIBLE:\n exception_class = ElementNotVisibleException\n elif status in ErrorCode.INVALID_ELEMENT_STATE:\n exception_class = InvalidElementStateException\n elif status in ErrorCode.INVALID_SELECTOR \\\n or status in ErrorCode.INVALID_XPATH_SELECTOR \\\n or status in ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER:\n exception_class = InvalidSelectorException\n elif status in ErrorCode.ELEMENT_IS_NOT_SELECTABLE:\n exception_class = ElementNotSelectableException\n elif status in ErrorCode.ELEMENT_NOT_INTERACTABLE:\n exception_class = ElementNotInteractableException\n elif status in ErrorCode.INVALID_COOKIE_DOMAIN:\n exception_class = InvalidCookieDomainException\n elif status in ErrorCode.UNABLE_TO_SET_COOKIE:\n exception_class = UnableToSetCookieException\n elif status in ErrorCode.TIMEOUT:\n exception_class = TimeoutException\n elif status in ErrorCode.SCRIPT_TIMEOUT:\n exception_class = TimeoutException\n elif status in ErrorCode.UNKNOWN_ERROR:\n exception_class = WebDriverException\n elif status in ErrorCode.UNEXPECTED_ALERT_OPEN:\n exception_class = UnexpectedAlertPresentException\n elif status in ErrorCode.NO_ALERT_OPEN:\n exception_class = NoAlertPresentException\n elif status in ErrorCode.IME_NOT_AVAILABLE:\n exception_class = ImeNotAvailableException\n elif status in ErrorCode.IME_ENGINE_ACTIVATION_FAILED:\n exception_class = ImeActivationFailedException\n elif status in ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS:\n exception_class = MoveTargetOutOfBoundsException\n elif status in ErrorCode.JAVASCRIPT_ERROR:\n exception_class = JavascriptException\n elif status in ErrorCode.SESSION_NOT_CREATED:\n exception_class = SessionNotCreatedException\n elif status in ErrorCode.INVALID_ARGUMENT:\n exception_class = InvalidArgumentException\n elif status in ErrorCode.NO_SUCH_COOKIE:\n exception_class = NoSuchCookieException\n elif status in ErrorCode.UNABLE_TO_CAPTURE_SCREEN:\n exception_class = ScreenshotException\n elif status in ErrorCode.ELEMENT_CLICK_INTERCEPTED:\n exception_class = ElementClickInterceptedException\n elif status in ErrorCode.INSECURE_CERTIFICATE:\n exception_class = InsecureCertificateException\n elif status in ErrorCode.INVALID_COORDINATES:\n exception_class = InvalidCoordinatesException\n elif status in ErrorCode.INVALID_SESSION_ID:\n exception_class = InvalidSessionIdException\n elif status in ErrorCode.UNKNOWN_METHOD:\n exception_class = UnknownMethodException\n else:\n exception_class = WebDriverException\n if value == '' or value is None:\n value = response['value']\n if isinstance(value, basestring):\n if exception_class == ErrorInResponseException:\n raise exception_class(response, value)\n raise exception_class(value)\n if message == \"\" and 'message' in value:\n message = value['message']\n \n screen = None\n if 'screen' in value:\n screen = value['screen']\n \n stacktrace = None\n if 'stackTrace' in value and value['stackTrace']:\n stacktrace = []\n try:\n for frame in value['stackTrace']:\n line = self._value_or_default(frame, 'lineNumber', '')\n file = self._value_or_default(frame, 'fileName', '')\n if line:\n file = \"%s:%s\" % (file, line)\n meth = self._value_or_default(frame, 'methodName', '')\n if 'className' in frame:\n meth = \"%s.%s\" % (frame['className'], meth)\n msg = \" at %s (%s)\"\n msg = msg % (meth, file)\n stacktrace.append(msg)\n except TypeError:\n pass\n if exception_class == ErrorInResponseException:\n raise exception_class(response, message)\n elif exception_class == UnexpectedAlertPresentException:\n alert_text = None\n if 'data' in value:\n alert_text = value['data'].get('text')\n elif 'alert' in value:\n alert_text = value['alert'].get('text')\n raise exception_class(message, screen, stacktrace, alert_text)\n> raise exception_class(message, screen, stacktrace)\nE selenium.common.exceptions.InvalidArgumentException: Message: 'unicodeKeyboard' must be of type boolean\n\n/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py:242: InvalidArgumentException"}, "attachments": [{"name": "log", "source": "a88b0ddc-fcd4-46ab-a869-913ef616ca03-attachment.txt", "type": "text/plain"}, {"name": "stdout", "source": "f096293f-0f79-49bc-a93d-6788cd87963e-attachment.txt", "type": "text/plain"}, {"name": "stderr", "source": "a2051384-2c1b-4333-acf7-82caaabfb634-attachment.txt", "type": "text/plain"}], "uuid": "2bea4b86-c208-4d39-b410-1f04505fcef7", "historyId": "61d0ec5868142760393bb75a0ddaae70", "fullName": "tests.test_vedio.test_videorelease.Test_videorelease#test_case1", "labels": [{"name": "parentSuite", "value": "tests.test_vedio"}, {"name": "suite", "value": "test_videorelease"}, {"name": "subSuite", "value": "Test_videorelease"}, {"name": "host", "value": "tangmaoheng-deMacBook-Air.local"}, {"name": "thread", "value": "14333-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "tests.test_vedio.test_videorelease"}]} -------------------------------------------------------------------------------- /report/xml/1bc24c7e-c484-46e9-95a5-66f76da9c067-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "53038d89-6061-47d7-99e6-b7bb8d0488d7", "children": ["8ed1175c-a332-4bea-adb4-174c2b07b451"], "befores": [{"name": "action", "status": "broken", "statusDetails": {"message": "TypeError: 'NoneType' object is not subscriptable\n", "trace": " File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pluggy/callers.py\", line 187, in _multicall\n res = hook_impl.function(*args)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 969, in pytest_fixture_setup\n result = call_fixture_func(fixturefunc, request, kwargs)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 824, in call_fixture_func\n res = next(it)\n File \"/Users/tmh/PycharmProjects/appauto/base/conftest_android.py\", line 58, in action\n element_action=ElementActions(driverenv)\n File \"/Users/tmh/PycharmProjects/appauto/base/utils.py\", line 15, in getinstance\n instances[class_] = class_(*args, **kwargs)\n File \"/Users/tmh/PycharmProjects/appauto/base/action.py\", line 30, in __init__\n self.width =self.Resolution[0]\n"}, "start": 1546833907614, "stop": 1546833907614}], "start": 1546833907614, "stop": 1546833907775} -------------------------------------------------------------------------------- /report/xml/1dea38e3-f7b0-4dc0-a433-f87c88c831cf-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "0fdc256c-1716-4bdc-adbf-eb42155b4f76", "children": ["b05bb154-aaa8-4937-abe3-336c5b066f1f"], "befores": [{"name": "action", "status": "passed", "start": 1546843137417, "stop": 1546843137418}], "afters": [{"name": "action::0", "status": "passed", "start": 1546843149537, "stop": 1546843149874}], "start": 1546843137417, "stop": 1546843149874} -------------------------------------------------------------------------------- /report/xml/1e68c468-f52e-42e1-8de8-087700dbe79d-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "90b51938-88b3-4c09-940e-bbb41443574d", "children": ["dcd5be3e-4d73-4b38-b2be-d28593a64d8f"], "befores": [{"name": "driverenv", "status": "passed", "start": 1546842411674, "stop": 1546842430356}], "start": 1546842411674, "stop": 1546842472979} -------------------------------------------------------------------------------- /report/xml/1f3702af-add8-40d9-a98a-bb55ca41e533-attachment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/1f3702af-add8-40d9-a98a-bb55ca41e533-attachment.png -------------------------------------------------------------------------------- /report/xml/21abedd4-d6b7-4210-b440-b78ea3791748-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "6b3098c1-1db6-4230-9578-d87576eefc2d", "children": ["dcd5be3e-4d73-4b38-b2be-d28593a64d8f"], "befores": [{"name": "action", "status": "passed", "start": 1546842430357, "stop": 1546842430357}], "afters": [{"name": "action::0", "status": "passed", "start": 1546842472744, "stop": 1546842472978}], "start": 1546842430357, "stop": 1546842472978} -------------------------------------------------------------------------------- /report/xml/23e0a33d-755d-495a-a7d3-662b31b63b3c-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/23e0a33d-755d-495a-a7d3-662b31b63b3c-attachment.txt -------------------------------------------------------------------------------- /report/xml/26cdddf9-e4d3-4591-940d-ec91e044d7ab-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/26cdddf9-e4d3-4591-940d-ec91e044d7ab-attachment.txt -------------------------------------------------------------------------------- /report/xml/28a2f24c-7f80-42fd-bd43-513f93f183cd-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "50756f64-0315-40d7-be91-7fefb36b3394", "children": ["5faf87c5-1454-43a1-bbd9-759771e9baf7"], "befores": [{"name": "action", "status": "passed", "start": 1546843185733, "stop": 1546843185733}], "afters": [{"name": "action::0", "status": "passed", "start": 1546843344195, "stop": 1546843344440}], "start": 1546843185733, "stop": 1546843344440} -------------------------------------------------------------------------------- /report/xml/2ae9ebdc-c8fc-4c99-b3a2-95e7cbf8e00a-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/2ae9ebdc-c8fc-4c99-b3a2-95e7cbf8e00a-attachment.txt -------------------------------------------------------------------------------- /report/xml/2fd16e0b-5cb0-458a-8e7d-c4c3104efea1-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/2fd16e0b-5cb0-458a-8e7d-c4c3104efea1-attachment.txt -------------------------------------------------------------------------------- /report/xml/30b95c23-126c-4ae8-a142-d5cb1b640503-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/30b95c23-126c-4ae8-a142-d5cb1b640503-attachment.txt -------------------------------------------------------------------------------- /report/xml/3169bc89-e5e3-409c-8f4c-e0900691703e-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/3169bc89-e5e3-409c-8f4c-e0900691703e-attachment.txt -------------------------------------------------------------------------------- /report/xml/32275fd0-7b26-458a-a314-d7f18c08c6bd-attachment.txt: -------------------------------------------------------------------------------- 1 | INFO 12:01:08 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': 'True', 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} -------------------------------------------------------------------------------- /report/xml/33712355-4cc3-45b2-aaf5-f94b0777b972-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "664c1590-7ff1-4f69-9e58-db9a83c3a9d6", "children": ["5faf87c5-1454-43a1-bbd9-759771e9baf7"], "befores": [{"name": "suitinit", "status": "passed", "start": 1546843185733, "stop": 1546843185733}], "start": 1546843185733, "stop": 1546843344195} -------------------------------------------------------------------------------- /report/xml/3502b925-0d38-4e4f-b528-038c9bc3cd66-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/3502b925-0d38-4e4f-b528-038c9bc3cd66-attachment.txt -------------------------------------------------------------------------------- /report/xml/3ad22042-0c49-4c4e-b81a-dd4bd5ce6787-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "0d639d59-3933-494f-bcae-b8fbab4eaeaa", "children": ["a1903318-27e1-451d-a652-4b1b792b37c2"], "befores": [{"name": "caserun", "status": "passed", "start": 1546833967877, "stop": 1546833967877}], "afters": [{"name": "caserun::0", "status": "passed", "attachments": [{"name": "用例结束前的截图_12:06:16_.png", "source": "e86819b3-9efe-4f9b-a8b3-5d4e53b10ddf-attachment.png", "type": "image/png"}], "start": 1546833975225, "stop": 1546833976984}], "start": 1546833967877, "stop": 1546833976984} -------------------------------------------------------------------------------- /report/xml/3ae6801d-bf4c-4c75-bde4-d39f7e033b65-attachment.txt: -------------------------------------------------------------------------------- 1 | INFO 12:04:55 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': True, 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} -------------------------------------------------------------------------------- /report/xml/4ac4ca22-d3f2-490b-96a3-e46dec73bdd9-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/4ac4ca22-d3f2-490b-96a3-e46dec73bdd9-attachment.txt -------------------------------------------------------------------------------- /report/xml/4b7ee5b5-f617-42c0-8155-a94b7d35185b-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "66d0acf8-8819-4625-996c-5eab6e3f1c60", "children": ["a1903318-27e1-451d-a652-4b1b792b37c2"], "befores": [{"name": "action", "status": "passed", "start": 1546833935128, "stop": 1546833935129}], "afters": [{"name": "action::0", "status": "passed", "start": 1546833976986, "stop": 1546833977192}], "start": 1546833935128, "stop": 1546833977192} -------------------------------------------------------------------------------- /report/xml/4c65ef77-5e6d-40e3-abbc-293b84cb4789-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "b0ec8b1d-d6d2-4834-9078-c697831a017c", "children": ["b996f37f-b761-49d5-87cc-f48af46bc2c7"], "befores": [{"name": "action", "status": "passed", "start": 1546843021515, "stop": 1546843021515}], "afters": [{"name": "action::0", "status": "passed", "start": 1546843039215, "stop": 1546843039436}], "start": 1546843021515, "stop": 1546843039437} -------------------------------------------------------------------------------- /report/xml/53891f13-2a0f-4734-8346-9ecfdec58401-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/53891f13-2a0f-4734-8346-9ecfdec58401-attachment.txt -------------------------------------------------------------------------------- /report/xml/543b24cf-ea3b-4ecf-b1ba-f5e4eaebf854-attachment.txt: -------------------------------------------------------------------------------- 1 | INFO 14:26:51 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': True, 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} 2 | 3 | INFO 14:27:10 start_activity: com.jm.android.jumei.home.activity.NewHomeActivity 4 | 5 | INFO 14:27:24 通过坐标(987.0,1483.0), 成功点击 页面【特卖首页】的元素【进入用户中心按钮】 6 | 7 | INFO 14:27:26 查找 页面【用户中心页】的元素【注册登陆】 8 | 9 | INFO 14:27:29 app已登陆 10 | 11 | INFO 14:27:29 start_activity: com.jm.android.jumei.home.activity.NewHomeActivity 12 | 13 | INFO 14:27:43 ————————————————————————执行用例 ----------—————————————— 14 | INFO 14:27:43 [点击] 页面【特卖首页】的元素【发布】 15 | 16 | INFO 14:27:45 [点击] 页面【视频发布页】的元素【发布】 17 | 18 | ERROR 14:27:50 【视频发布页】页面中未能找到元素【发布】 19 | locator: 20 | {'name': '发布', 'type': 'id', 'value': 'com.jm.android.jumei:id/social_publish_submit', 'dynamic': False, 'switch': None, 'page': '视频发布页'} 21 | INFO 14:27:50 sleep等待 1 s 22 | 23 | INFO 14:27:52 ————————————————————————该用例执行结束 ----------—————————————— -------------------------------------------------------------------------------- /report/xml/546e3c42-6610-42b9-a6a3-06872878ce73-attachment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/546e3c42-6610-42b9-a6a3-06872878ce73-attachment.png -------------------------------------------------------------------------------- /report/xml/55c612c9-8a4b-4723-b3b5-a914d236080e-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "8e687801-f725-442e-975a-155244bdc10a", "children": ["dcd5be3e-4d73-4b38-b2be-d28593a64d8f"], "befores": [{"name": "caserun", "status": "passed", "start": 1546842463042, "stop": 1546842463043}], "afters": [{"name": "caserun::0", "status": "passed", "attachments": [{"name": "用例结束前的截图_14:27:52_.png", "source": "cf4e24b4-07eb-47d6-9eed-48f3f76db6f7-attachment.png", "type": "image/png"}], "start": 1546842470983, "stop": 1546842472743}], "start": 1546842463042, "stop": 1546842472743} -------------------------------------------------------------------------------- /report/xml/594817c9-9d9b-4b67-be5a-239b5f5d30e4-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/594817c9-9d9b-4b67-be5a-239b5f5d30e4-attachment.txt -------------------------------------------------------------------------------- /report/xml/5af2875d-ab16-472c-9b24-d38ebe68eaf6-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "bce2c06f-fda0-4a89-9512-1fbb0b3872b8", "children": ["b05bb154-aaa8-4937-abe3-336c5b066f1f"], "befores": [{"name": "caserun", "status": "passed", "start": 1546843137418, "stop": 1546843137418}], "afters": [{"name": "caserun::0", "status": "passed", "attachments": [{"name": "用例结束前的截图_14:39:09_.png", "source": "0d40c3e0-f16c-4f30-9208-348a2d7134ae-attachment.png", "type": "image/png"}], "start": 1546843146619, "stop": 1546843149534}], "start": 1546843137418, "stop": 1546843149534} -------------------------------------------------------------------------------- /report/xml/5ca2bb07-6737-4e95-9568-20b93df13c26-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/5ca2bb07-6737-4e95-9568-20b93df13c26-attachment.txt -------------------------------------------------------------------------------- /report/xml/5d57814e-f7f3-4c4c-b78a-ce7b9fe3d9d7-attachment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/5d57814e-f7f3-4c4c-b78a-ce7b9fe3d9d7-attachment.png -------------------------------------------------------------------------------- /report/xml/603aa3ba-f091-4d66-af51-ec1e5e48a621-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/603aa3ba-f091-4d66-af51-ec1e5e48a621-attachment.txt -------------------------------------------------------------------------------- /report/xml/60476879-f3f9-4989-b775-4fd9fb8a50fa-attachment.txt: -------------------------------------------------------------------------------- 1 | INFO 14:36:51 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': True, 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} 2 | 3 | INFO 14:37:01 ————————————————————————执行用例 ----------—————————————— 4 | INFO 14:37:01 [点击] 页面【特卖首页】的元素【发布】 5 | 6 | INFO 14:37:07 [点击] 页面【特卖首页】的元素【上传视频】 7 | 8 | INFO 14:37:10 [点击] 页面【视频发布页】的元素【发布】 9 | 10 | ERROR 14:37:16 【视频发布页】页面中未能找到元素【发布】 11 | locator: 12 | {'name': '发布', 'type': 'id', 'value': 'com.jm.android.jumei:id/social_publish_submit', 'dynamic': False, 'switch': None, 'page': '视频发布页'} 13 | INFO 14:37:16 sleep等待 1 s 14 | 15 | INFO 14:37:19 ————————————————————————该用例执行结束 ----------—————————————— -------------------------------------------------------------------------------- /report/xml/62e86b44-98ef-4aca-bbba-48f145555a82-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "98e50c8d-af82-4f1c-bb98-8dc1c544d348", "children": ["b996f37f-b761-49d5-87cc-f48af46bc2c7"], "befores": [{"name": "driverenv", "status": "passed", "start": 1546843011039, "stop": 1546843021515}], "start": 1546843011039, "stop": 1546843039438} -------------------------------------------------------------------------------- /report/xml/692fbc9d-702d-4d9b-9a59-bb7e00f89f4b-result.json: -------------------------------------------------------------------------------- 1 | {"name": "test_case1", "status": "broken", "statusDetails": {"message": "TypeError: 'WebElement' object does not support indexing", "trace": "self = , action = \n\n def test_case1(self,action):\n count=5\n action.click(p.特卖首页.发布)\n \n for index in range(count):\n action.click(p.特卖首页.发布_上传视频)\n> videoele=action.find_ele(vp.视频发布页.视频选择)[0]\nE TypeError: 'WebElement' object does not support indexing\n\ntests/test_vedio/test_videorelease.py:19: TypeError"}, "attachments": [{"name": "log", "source": "0ac8a7b4-ca14-4f30-8048-929374fc143d-attachment.txt", "type": "text/plain"}, {"name": "stdout", "source": "594817c9-9d9b-4b67-be5a-239b5f5d30e4-attachment.txt", "type": "text/plain"}, {"name": "stderr", "source": "603aa3ba-f091-4d66-af51-ec1e5e48a621-attachment.txt", "type": "text/plain"}], "start": 1546843137419, "stop": 1546843146535, "uuid": "b05bb154-aaa8-4937-abe3-336c5b066f1f", "historyId": "61d0ec5868142760393bb75a0ddaae70", "fullName": "tests.test_vedio.test_videorelease.Test_videorelease#test_case1", "labels": [{"name": "parentSuite", "value": "tests.test_vedio"}, {"name": "suite", "value": "test_videorelease"}, {"name": "subSuite", "value": "Test_videorelease"}, {"name": "host", "value": "tangmaoheng-deMacBook-Air.local"}, {"name": "thread", "value": "15490-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "tests.test_vedio.test_videorelease"}]} -------------------------------------------------------------------------------- /report/xml/6fce2fca-f78d-4b6f-86e4-61486ae7a5da-attachment.txt: -------------------------------------------------------------------------------- 1 | INFO 14:39:35 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': True, 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} 2 | 3 | INFO 14:39:45 ————————————————————————执行用例 ----------—————————————— 4 | INFO 14:39:45 [点击] 页面【特卖首页】的元素【发布】 5 | 6 | INFO 14:39:52 [点击] 页面【特卖首页】的元素【上传视频】 7 | 8 | INFO 14:39:54 查找 页面【视频发布页】的元素【视频选择】 9 | 10 | INFO 14:39:55 [点击]1次元素 11 | 12 | INFO 14:39:56 [点击] 页面【视频发布页】的元素【选择后下一步】 13 | 14 | INFO 14:39:58 [点击] 页面【视频发布页】的元素【处理后下一步】 15 | 16 | INFO 14:40:00 sleep等待 7 s 17 | 18 | INFO 14:40:07 [点击] 页面【视频发布页】的元素【视频发布】 19 | 20 | INFO 14:40:25 当前页面成功找到toast: 视频发布成功 21 | 22 | INFO 14:40:25 result: True 23 | 24 | INFO 14:40:26 [点击] 页面【特卖首页】的元素【上传视频】 25 | 26 | INFO 14:40:29 查找 页面【视频发布页】的元素【视频选择】 27 | 28 | INFO 14:40:30 [点击]1次元素 29 | 30 | INFO 14:40:30 [点击] 页面【视频发布页】的元素【选择后下一步】 31 | 32 | INFO 14:40:32 [点击] 页面【视频发布页】的元素【处理后下一步】 33 | 34 | INFO 14:40:34 sleep等待 7 s 35 | 36 | INFO 14:40:41 [点击] 页面【视频发布页】的元素【视频发布】 37 | 38 | INFO 14:40:52 当前页面成功找到toast: 视频发布成功 39 | 40 | INFO 14:40:52 result: True 41 | 42 | INFO 14:40:53 [点击] 页面【特卖首页】的元素【上传视频】 43 | 44 | INFO 14:40:56 查找 页面【视频发布页】的元素【视频选择】 45 | 46 | INFO 14:40:56 [点击]1次元素 47 | 48 | INFO 14:40:57 [点击] 页面【视频发布页】的元素【选择后下一步】 49 | 50 | INFO 14:40:59 [点击] 页面【视频发布页】的元素【处理后下一步】 51 | 52 | INFO 14:41:01 sleep等待 7 s 53 | 54 | INFO 14:41:08 [点击] 页面【视频发布页】的元素【视频发布】 55 | 56 | INFO 14:41:19 当前页面成功找到toast: 视频发布成功 57 | 58 | INFO 14:41:19 result: True 59 | 60 | INFO 14:41:21 [点击] 页面【特卖首页】的元素【上传视频】 61 | 62 | INFO 14:41:24 查找 页面【视频发布页】的元素【视频选择】 63 | 64 | INFO 14:41:24 [点击]1次元素 65 | 66 | INFO 14:41:24 [点击] 页面【视频发布页】的元素【选择后下一步】 67 | 68 | INFO 14:41:27 [点击] 页面【视频发布页】的元素【处理后下一步】 69 | 70 | INFO 14:41:28 sleep等待 7 s 71 | 72 | INFO 14:41:35 [点击] 页面【视频发布页】的元素【视频发布】 73 | 74 | INFO 14:41:49 当前页面成功找到toast: 视频发布成功 75 | 76 | INFO 14:41:49 result: True 77 | 78 | INFO 14:41:50 [点击] 页面【特卖首页】的元素【上传视频】 79 | 80 | INFO 14:41:53 查找 页面【视频发布页】的元素【视频选择】 81 | 82 | INFO 14:41:54 [点击]1次元素 83 | 84 | INFO 14:41:54 [点击] 页面【视频发布页】的元素【选择后下一步】 85 | 86 | INFO 14:41:56 [点击] 页面【视频发布页】的元素【处理后下一步】 87 | 88 | INFO 14:41:58 sleep等待 7 s 89 | 90 | INFO 14:42:05 [点击] 页面【视频发布页】的元素【视频发布】 91 | 92 | INFO 14:42:20 当前页面成功找到toast: 视频发布成功 93 | 94 | INFO 14:42:20 result: True 95 | INFO 14:42:22 sleep等待 1 s 96 | 97 | INFO 14:42:24 ————————————————————————该用例执行结束 ----------—————————————— -------------------------------------------------------------------------------- /report/xml/768689ab-c326-42c8-9f8a-dadf37c12f1d-attachment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/768689ab-c326-42c8-9f8a-dadf37c12f1d-attachment.png -------------------------------------------------------------------------------- /report/xml/838e8e5d-a86c-44d3-8052-f3cf5c33015d-result.json: -------------------------------------------------------------------------------- 1 | {"name": "test_case1", "status": "passed", "attachments": [{"name": "上传后截图_14:40:26_.png", "source": "d16749bf-9001-464c-b099-3ad7d11ab059-attachment.png", "type": "image/png"}, {"name": "上传后截图_14:40:53_.png", "source": "b67ce731-621d-4b68-ac43-4c9487b043cb-attachment.png", "type": "image/png"}, {"name": "上传后截图_14:41:21_.png", "source": "768689ab-c326-42c8-9f8a-dadf37c12f1d-attachment.png", "type": "image/png"}, {"name": "上传后截图_14:41:50_.png", "source": "546e3c42-6610-42b9-a6a3-06872878ce73-attachment.png", "type": "image/png"}, {"name": "上传后截图_14:42:22_.png", "source": "968c72e1-375b-4648-9190-a7133f0ffd6b-attachment.png", "type": "image/png"}, {"name": "log", "source": "6fce2fca-f78d-4b6f-86e4-61486ae7a5da-attachment.txt", "type": "text/plain"}, {"name": "stdout", "source": "26cdddf9-e4d3-4591-940d-ec91e044d7ab-attachment.txt", "type": "text/plain"}, {"name": "stderr", "source": "30b95c23-126c-4ae8-a142-d5cb1b640503-attachment.txt", "type": "text/plain"}], "start": 1546843185735, "stop": 1546843342535, "uuid": "5faf87c5-1454-43a1-bbd9-759771e9baf7", "historyId": "61d0ec5868142760393bb75a0ddaae70", "fullName": "tests.test_vedio.test_videorelease.Test_videorelease#test_case1", "labels": [{"name": "parentSuite", "value": "tests.test_vedio"}, {"name": "suite", "value": "test_videorelease"}, {"name": "subSuite", "value": "Test_videorelease"}, {"name": "host", "value": "tangmaoheng-deMacBook-Air.local"}, {"name": "thread", "value": "15614-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "tests.test_vedio.test_videorelease"}]} -------------------------------------------------------------------------------- /report/xml/86139c2a-aea2-47d8-b30a-5eef2e73f365-attachment.txt: -------------------------------------------------------------------------------- 1 | INFO 12:03:51 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': True, 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} -------------------------------------------------------------------------------- /report/xml/8ada9ae0-65b8-43d7-88f9-68d5851714b3-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/8ada9ae0-65b8-43d7-88f9-68d5851714b3-attachment.txt -------------------------------------------------------------------------------- /report/xml/8d106794-b06d-45ef-a568-c85e52e0b9ba-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "d649aef6-e7ce-4019-9f36-2324472fdf27", "children": ["b4e756f8-126c-4094-b908-95c5d947a2e3"], "befores": [{"name": "driverenv", "status": "passed", "start": 1546833831871, "stop": 1546833843506}], "start": 1546833831871, "stop": 1546833843724} -------------------------------------------------------------------------------- /report/xml/915741d4-fe12-4e39-aa4a-574089abd8cd-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "5e1bb74d-7df0-4056-8946-f26a300ecb52", "children": ["b996f37f-b761-49d5-87cc-f48af46bc2c7"], "befores": [{"name": "caserun", "status": "passed", "start": 1546843021516, "stop": 1546843021516}], "afters": [{"name": "caserun::0", "status": "passed", "attachments": [{"name": "用例结束前的截图_14:37:19_.png", "source": "1f3702af-add8-40d9-a98a-bb55ca41e533-attachment.png", "type": "image/png"}], "start": 1546843036385, "stop": 1546843039213}], "start": 1546843021516, "stop": 1546843039213} -------------------------------------------------------------------------------- /report/xml/968c72e1-375b-4648-9190-a7133f0ffd6b-attachment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/968c72e1-375b-4648-9190-a7133f0ffd6b-attachment.png -------------------------------------------------------------------------------- /report/xml/9dfd1b3b-8101-4f15-8c5b-4dcad7ea0021-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "1321a764-35e8-4812-b085-8ecb11e0a4d1", "children": ["b05bb154-aaa8-4937-abe3-336c5b066f1f"], "befores": [{"name": "suitinit", "status": "passed", "start": 1546843137418, "stop": 1546843137418}], "start": 1546843137418, "stop": 1546843149535} -------------------------------------------------------------------------------- /report/xml/9f048740-a1ce-4fb2-97c1-ae5f9a198688-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "22ae8274-fcaa-4ded-ba3b-6a41adc2aa58", "children": ["8ed1175c-a332-4bea-adb4-174c2b07b451"], "befores": [{"name": "driverenv", "status": "passed", "start": 1546833895152, "stop": 1546833907614}], "start": 1546833895152, "stop": 1546833907776} -------------------------------------------------------------------------------- /report/xml/a2051384-2c1b-4333-acf7-82caaabfb634-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/a2051384-2c1b-4333-acf7-82caaabfb634-attachment.txt -------------------------------------------------------------------------------- /report/xml/a224c455-7342-41b7-8bd3-d9ba8a137764-attachment.txt: -------------------------------------------------------------------------------- 1 | INFO 12:03:33 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': 'True', 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} -------------------------------------------------------------------------------- /report/xml/a567b8aa-bfab-4890-a82f-02e2d99cefcb-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "d32efbfe-0c7b-4663-bb01-2579a0810a56", "children": ["ffd28baa-d57c-4d9f-acae-491643a8db18"], "befores": [{"name": "driverenv", "status": "broken", "statusDetails": {"message": "selenium.common.exceptions.InvalidArgumentException: Message: 'unicodeKeyboard' must be of type boolean\n\n", "trace": " File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pluggy/callers.py\", line 187, in _multicall\n res = hook_impl.function(*args)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 969, in pytest_fixture_setup\n result = call_fixture_func(fixturefunc, request, kwargs)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 828, in call_fixture_func\n res = fixturefunc(**kwargs)\n File \"/Users/tmh/PycharmProjects/appauto/base/conftest_android.py\", line 49, in driverenv\n driver = webdriver.Remote(host, capabilities)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/appium/webdriver/webdriver.py\", line 97, in __init__\n super(WebDriver, self).__init__(command_executor, desired_capabilities, browser_profile, proxy, keep_alive)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py\", line 157, in __init__\n self.start_session(capabilities, browser_profile)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/appium/webdriver/webdriver.py\", line 138, in start_session\n response = self.execute(RemoteCommand.NEW_SESSION, parameters)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py\", line 321, in execute\n self.error_handler.check_response(response)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py\", line 242, in check_response\n raise exception_class(message, screen, stacktrace)\n"}, "start": 1546833668012, "stop": 1546833668453}], "start": 1546833668012, "stop": 1546833669158} -------------------------------------------------------------------------------- /report/xml/a88b0ddc-fcd4-46ab-a869-913ef616ca03-attachment.txt: -------------------------------------------------------------------------------- 1 | INFO 12:03:25 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': 'True', 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} -------------------------------------------------------------------------------- /report/xml/acb7cda0-b685-4444-9f5e-4d6035c665bc-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "d085cce9-36b4-411f-8e2d-4b4f0f1ab23e", "children": ["2bea4b86-c208-4d39-b410-1f04505fcef7"], "befores": [{"name": "driverenv", "status": "broken", "statusDetails": {"message": "selenium.common.exceptions.InvalidArgumentException: Message: 'unicodeKeyboard' must be of type boolean\n\n", "trace": " File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pluggy/callers.py\", line 187, in _multicall\n res = hook_impl.function(*args)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 969, in pytest_fixture_setup\n result = call_fixture_func(fixturefunc, request, kwargs)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 828, in call_fixture_func\n res = fixturefunc(**kwargs)\n File \"/Users/tmh/PycharmProjects/appauto/base/conftest_android.py\", line 50, in driverenv\n driver = webdriver.Remote(host, capabilities)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/appium/webdriver/webdriver.py\", line 97, in __init__\n super(WebDriver, self).__init__(command_executor, desired_capabilities, browser_profile, proxy, keep_alive)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py\", line 157, in __init__\n self.start_session(capabilities, browser_profile)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/appium/webdriver/webdriver.py\", line 138, in start_session\n response = self.execute(RemoteCommand.NEW_SESSION, parameters)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py\", line 321, in execute\n self.error_handler.check_response(response)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py\", line 242, in check_response\n raise exception_class(message, screen, stacktrace)\n"}, "start": 1546833805075, "stop": 1546833805106}], "start": 1546833805075, "stop": 1546833805334} -------------------------------------------------------------------------------- /report/xml/b67ce731-621d-4b68-ac43-4c9487b043cb-attachment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/b67ce731-621d-4b68-ac43-4c9487b043cb-attachment.png -------------------------------------------------------------------------------- /report/xml/b9329203-7a34-47ed-8e83-c0ca0d5fe236-result.json: -------------------------------------------------------------------------------- 1 | {"name": "test_case1", "status": "broken", "statusDetails": {"message": "base.verify.NotFoundElementError", "trace": "self = , locator = {'dynamic': False, 'name': '发布', 'page': '视频发布页', 'switch': None, ...}, is_need_displayed = True, wait = 5, is_raise = True\n\n def _find_element(self, locator, is_need_displayed=True,wait = 5,is_raise=True):\n \"\"\"查找单个元素,如果有多个返回第一个\n \n Args:\n locator: 定位器\n is_need_displayed: 是否需要定位的元素必须展示\n is_raise: 是否抛出异常\n \n Returns: 元素 ,没找到返回 None\n \n Raises: NotFoundElementError\n 未找到元素会抛 NotFoundElementError 异常\n \n \"\"\"\n \n waittime_count=Waittime_count(msg='[查找] 页面【{}】该元素【{}】等待时间:'.format(locator.get(\"page\"),locator.get(\"name\")))\n waittime_count.start()\n try:\n if is_need_displayed:\n WebDriverWait(self.driver, wait).until(\n> lambda driver: self._get_element_by_type(driver, locator).is_displayed())\n\nbase/action.py:575: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\nself = , method = . at 0x10406b6a8>\nmessage = ''\n\n def until(self, method, message=''):\n \"\"\"Calls the method provided with the driver as an argument until the \\\n return value is not False.\"\"\"\n screen = None\n stacktrace = None\n \n end_time = time.time() + self._timeout\n while True:\n try:\n value = method(self._driver)\n if value:\n return value\n except self._ignored_exceptions as exc:\n screen = getattr(exc, 'screen', None)\n stacktrace = getattr(exc, 'stacktrace', None)\n time.sleep(self._poll)\n if time.time() > end_time:\n break\n> raise TimeoutException(message, screen, stacktrace)\nE selenium.common.exceptions.TimeoutException: Message:\n\n/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/support/wait.py:80: TimeoutException\n\nDuring handling of the above exception, another exception occurred:\n\nself = , action = \n\n def test_case1(self,action):\n count=5\n action.click(p.特卖首页.发布)\n \n for index in range(count):\n action.click(p.特卖首页.发布_上传视频)\n> action.click(vp.视频发布页.视频发布)\n\ntests/test_vedio/test_videorelease.py:19: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\nbase/action.py:329: in click\n element = self._find_element(locator,wait=wait)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\nself = , locator = {'dynamic': False, 'name': '发布', 'page': '视频发布页', 'switch': None, ...}, is_need_displayed = True, wait = 5, is_raise = True\n\n def _find_element(self, locator, is_need_displayed=True,wait = 5,is_raise=True):\n \"\"\"查找单个元素,如果有多个返回第一个\n \n Args:\n locator: 定位器\n is_need_displayed: 是否需要定位的元素必须展示\n is_raise: 是否抛出异常\n \n Returns: 元素 ,没找到返回 None\n \n Raises: NotFoundElementError\n 未找到元素会抛 NotFoundElementError 异常\n \n \"\"\"\n \n waittime_count=Waittime_count(msg='[查找] 页面【{}】该元素【{}】等待时间:'.format(locator.get(\"page\"),locator.get(\"name\")))\n waittime_count.start()\n try:\n if is_need_displayed:\n WebDriverWait(self.driver, wait).until(\n lambda driver: self._get_element_by_type(driver, locator).is_displayed())\n else:\n WebDriverWait(self.driver, wait).until(\n lambda driver: self._get_element_by_type(driver, locator) is not None)\n \n waittime_count.end()\n return self._get_element_by_type(self.driver, locator)\n except Exception as e:\n \n if is_raise==True:\n log.error(\n \"【{}】页面中未能找到元素【{}】\\n locator: \\n {}\".format(locator.get(\"page\"), locator.get(\"name\"), locator))\n> raise NotFoundElementError\nE base.verify.NotFoundElementError\n\nbase/action.py:587: NotFoundElementError"}, "attachments": [{"name": "log", "source": "60476879-f3f9-4989-b775-4fd9fb8a50fa-attachment.txt", "type": "text/plain"}, {"name": "stdout", "source": "4ac4ca22-d3f2-490b-96a3-e46dec73bdd9-attachment.txt", "type": "text/plain"}, {"name": "stderr", "source": "bc21fc83-a9c9-4c05-8cd8-523b9d63276e-attachment.txt", "type": "text/plain"}], "start": 1546843021518, "stop": 1546843036235, "uuid": "b996f37f-b761-49d5-87cc-f48af46bc2c7", "historyId": "61d0ec5868142760393bb75a0ddaae70", "fullName": "tests.test_vedio.test_videorelease.Test_videorelease#test_case1", "labels": [{"name": "parentSuite", "value": "tests.test_vedio"}, {"name": "suite", "value": "test_videorelease"}, {"name": "subSuite", "value": "Test_videorelease"}, {"name": "host", "value": "tangmaoheng-deMacBook-Air.local"}, {"name": "thread", "value": "15359-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "tests.test_vedio.test_videorelease"}]} -------------------------------------------------------------------------------- /report/xml/bc21fc83-a9c9-4c05-8cd8-523b9d63276e-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/bc21fc83-a9c9-4c05-8cd8-523b9d63276e-attachment.txt -------------------------------------------------------------------------------- /report/xml/be0b3314-b044-4202-a652-1ca30442a1d7-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "a5b5fcfe-161e-4331-89e1-ab349b50f3e7", "children": ["b996f37f-b761-49d5-87cc-f48af46bc2c7"], "befores": [{"name": "suitinit", "status": "passed", "start": 1546843021515, "stop": 1546843021515}], "start": 1546843021515, "stop": 1546843039215} -------------------------------------------------------------------------------- /report/xml/c8e6ad99-cf28-4e05-a155-fd41b3aa3970-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/c8e6ad99-cf28-4e05-a155-fd41b3aa3970-attachment.txt -------------------------------------------------------------------------------- /report/xml/cb2f0c04-b71a-4e1b-bc30-1f6d5ea55554-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "030bf64c-1f7c-4abe-baf2-d172a420ae2b", "children": ["5faf87c5-1454-43a1-bbd9-759771e9baf7"], "befores": [{"name": "driverenv", "status": "passed", "start": 1546843175425, "stop": 1546843185733}], "start": 1546843175425, "stop": 1546843344441} -------------------------------------------------------------------------------- /report/xml/cd40a3d8-7d79-46eb-a773-f8d8ce6c3cea-result.json: -------------------------------------------------------------------------------- 1 | {"name": "test_case1", "status": "broken", "statusDetails": {"message": "TypeError: 'NoneType' object is not subscriptable", "trace": "> lambda: ihook(item=item, **kwds),\n when=when,\n )\n\n/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/flaky/flaky_pytest_plugin.py:273: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\nbase/conftest_android.py:58: in action\n element_action=ElementActions(driverenv)\nbase/utils.py:15: in getinstance\n instances[class_] = class_(*args, **kwargs)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\nself = , driver = \n\n def __init__(self, driver: webdriver.Remote):\n self.driver = driver\n self.env = EnvironmentAndroid()\n #通过driver.get_window_size()获取的分辨率会不准确,所以读取配置的Resolution\n self.Resolution =self.env.current_device.get('Resolution')\n \n if self.Resolution==None:\n Resolution=[1080, 1920]\n \n> self.width =self.Resolution[0]\nE TypeError: 'NoneType' object is not subscriptable\n\nbase/action.py:30: TypeError"}, "attachments": [{"name": "log", "source": "3ae6801d-bf4c-4c75-bde4-d39f7e033b65-attachment.txt", "type": "text/plain"}, {"name": "stdout", "source": "c8e6ad99-cf28-4e05-a155-fd41b3aa3970-attachment.txt", "type": "text/plain"}, {"name": "stderr", "source": "5ca2bb07-6737-4e95-9568-20b93df13c26-attachment.txt", "type": "text/plain"}], "uuid": "8ed1175c-a332-4bea-adb4-174c2b07b451", "historyId": "61d0ec5868142760393bb75a0ddaae70", "fullName": "tests.test_vedio.test_videorelease.Test_videorelease#test_case1", "labels": [{"name": "parentSuite", "value": "tests.test_vedio"}, {"name": "suite", "value": "test_videorelease"}, {"name": "subSuite", "value": "Test_videorelease"}, {"name": "host", "value": "tangmaoheng-deMacBook-Air.local"}, {"name": "thread", "value": "14622-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "tests.test_vedio.test_videorelease"}]} -------------------------------------------------------------------------------- /report/xml/cee3e787-7ac9-431e-be59-7a3649a01f9b-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "eef26918-ee71-4e8f-a72b-b44a3fd02f95", "children": ["3e1eed3f-54d0-42db-8197-a31a8daf8091"], "befores": [{"name": "driverenv", "status": "broken", "statusDetails": {"message": "selenium.common.exceptions.InvalidArgumentException: Message: 'unicodeKeyboard' must be of type boolean\n\n", "trace": " File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pluggy/callers.py\", line 187, in _multicall\n res = hook_impl.function(*args)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 969, in pytest_fixture_setup\n result = call_fixture_func(fixturefunc, request, kwargs)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 828, in call_fixture_func\n res = fixturefunc(**kwargs)\n File \"/Users/tmh/PycharmProjects/appauto/base/conftest_android.py\", line 50, in driverenv\n driver = webdriver.Remote(host, capabilities)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/appium/webdriver/webdriver.py\", line 97, in __init__\n super(WebDriver, self).__init__(command_executor, desired_capabilities, browser_profile, proxy, keep_alive)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py\", line 157, in __init__\n self.start_session(capabilities, browser_profile)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/appium/webdriver/webdriver.py\", line 138, in start_session\n response = self.execute(RemoteCommand.NEW_SESSION, parameters)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py\", line 321, in execute\n self.error_handler.check_response(response)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py\", line 242, in check_response\n raise exception_class(message, screen, stacktrace)\n"}, "start": 1546833813258, "stop": 1546833813389}], "start": 1546833813258, "stop": 1546833813997} -------------------------------------------------------------------------------- /report/xml/cf4e24b4-07eb-47d6-9eed-48f3f76db6f7-attachment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/cf4e24b4-07eb-47d6-9eed-48f3f76db6f7-attachment.png -------------------------------------------------------------------------------- /report/xml/d16749bf-9001-464c-b099-3ad7d11ab059-attachment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/d16749bf-9001-464c-b099-3ad7d11ab059-attachment.png -------------------------------------------------------------------------------- /report/xml/d250f3a8-fd22-49dd-a10f-97aaad63a8dc-attachment.txt: -------------------------------------------------------------------------------- 1 | INFO 12:05:22 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'systemPort': 8201, 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': True, 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} 2 | 3 | INFO 12:05:35 start_activity: com.jm.android.jumei.home.activity.NewHomeActivity 4 | 5 | INFO 12:05:49 通过坐标(987.0,1483.0), 成功点击 页面【特卖首页】的元素【进入用户中心按钮】 6 | 7 | INFO 12:05:51 查找 页面【用户中心页】的元素【注册登陆】 8 | 9 | INFO 12:05:53 app已登陆 10 | 11 | INFO 12:05:53 start_activity: com.jm.android.jumei.home.activity.NewHomeActivity 12 | 13 | INFO 12:06:07 ————————————————————————执行用例 ----------—————————————— 14 | INFO 12:06:07 [点击] 页面【特卖首页】的元素【发布】 15 | 16 | INFO 12:06:10 [点击] 页面【视频发布页】的元素【发布】 17 | 18 | ERROR 12:06:15 【视频发布页】页面中未能找到元素【发布】 19 | locator: 20 | {'name': '发布', 'type': 'id', 'value': 'com.jm.android.jumei:id/social_publish_submit', 'dynamic': False, 'switch': None, 'page': '视频发布页'} 21 | INFO 12:06:15 sleep等待 1 s 22 | 23 | INFO 12:06:16 ————————————————————————该用例执行结束 ----------—————————————— -------------------------------------------------------------------------------- /report/xml/d2f040e2-5930-4b7b-a29c-fd91ee2aa005-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "09d4b4ce-7c3b-4795-bbd5-180d3257f14f", "children": ["b05bb154-aaa8-4937-abe3-336c5b066f1f"], "befores": [{"name": "driverenv", "status": "passed", "start": 1546843126673, "stop": 1546843137417}], "start": 1546843126673, "stop": 1546843149876} -------------------------------------------------------------------------------- /report/xml/d7af59e8-f39b-43d4-b868-696892792deb-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/d7af59e8-f39b-43d4-b868-696892792deb-attachment.txt -------------------------------------------------------------------------------- /report/xml/d843718e-d2d1-4fb8-a491-c8d73570195f-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/d843718e-d2d1-4fb8-a491-c8d73570195f-attachment.txt -------------------------------------------------------------------------------- /report/xml/da029da3-6ab3-4591-b2f2-ea2efbfb1cdf-attachment.txt: -------------------------------------------------------------------------------- 1 | INFO 12:00:41 当前执行的appium相关配置为:{'platformName': 'Android', 'platformVersion': '8.1.0', 'deviceName': '2425a80b', 'udid': '2425a80b', 'app': '/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk', 'clearSystemFiles': True, 'appActivity': 'com.jm.android.jumei.home.activity.StartActivity', 'appPackage': 'com.jm.android.jumei', 'automationName': 'UIAutomator2', 'noSign': True, 'recreateChromeDriverSessions': True, 'unicodeKeyboard': 'True', 'noReset': True, 'fullReset': False, 'newCommandTimeout': 300} -------------------------------------------------------------------------------- /report/xml/da44832c-0a1a-4e54-aab3-88269f1306ff-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/da44832c-0a1a-4e54-aab3-88269f1306ff-attachment.txt -------------------------------------------------------------------------------- /report/xml/e1692a5e-2dab-4591-977a-87ae6dfd595b-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "79f90fa6-eaaa-4fa6-ab3d-a4063fdc4e94", "children": ["5faf87c5-1454-43a1-bbd9-759771e9baf7"], "befores": [{"name": "caserun", "status": "passed", "start": 1546843185733, "stop": 1546843185734}], "afters": [{"name": "caserun::0", "status": "passed", "attachments": [{"name": "用例结束前的截图_14:42:24_.png", "source": "5d57814e-f7f3-4c4c-b78a-ce7b9fe3d9d7-attachment.png", "type": "image/png"}], "start": 1546843342536, "stop": 1546843344193}], "start": 1546843185733, "stop": 1546843344194} -------------------------------------------------------------------------------- /report/xml/e20bb103-bd3a-4fc4-b0e5-b3a26482839c-result.json: -------------------------------------------------------------------------------- 1 | {"name": "test_case1", "status": "broken", "statusDetails": {"message": "base.verify.NotFoundElementError", "trace": "self = , locator = {'dynamic': False, 'name': '发布', 'page': '视频发布页', 'switch': None, ...}, is_need_displayed = True, wait = 5, is_raise = True\n\n def _find_element(self, locator, is_need_displayed=True,wait = 5,is_raise=True):\n \"\"\"查找单个元素,如果有多个返回第一个\n \n Args:\n locator: 定位器\n is_need_displayed: 是否需要定位的元素必须展示\n is_raise: 是否抛出异常\n \n Returns: 元素 ,没找到返回 None\n \n Raises: NotFoundElementError\n 未找到元素会抛 NotFoundElementError 异常\n \n \"\"\"\n \n waittime_count=Waittime_count(msg='[查找] 页面【{}】该元素【{}】等待时间:'.format(locator.get(\"page\"),locator.get(\"name\")))\n waittime_count.start()\n try:\n if is_need_displayed:\n WebDriverWait(self.driver, wait).until(\n> lambda driver: self._get_element_by_type(driver, locator).is_displayed())\n\nbase/action.py:575: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\nself = , method = . at 0x10ba7b730>\nmessage = ''\n\n def until(self, method, message=''):\n \"\"\"Calls the method provided with the driver as an argument until the \\\n return value is not False.\"\"\"\n screen = None\n stacktrace = None\n \n end_time = time.time() + self._timeout\n while True:\n try:\n value = method(self._driver)\n if value:\n return value\n except self._ignored_exceptions as exc:\n screen = getattr(exc, 'screen', None)\n stacktrace = getattr(exc, 'stacktrace', None)\n time.sleep(self._poll)\n if time.time() > end_time:\n break\n> raise TimeoutException(message, screen, stacktrace)\nE selenium.common.exceptions.TimeoutException: Message:\n\n/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/support/wait.py:80: TimeoutException\n\nDuring handling of the above exception, another exception occurred:\n\nself = , action = \n\n def test_case1(self,action):\n count=5\n action.click(p.特卖首页.发布)\n \n for index in range(count):\n> action.click(vp.视频发布页.视频发布)\n\ntests/test_vedio/test_videorelease.py:18: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\nbase/action.py:329: in click\n element = self._find_element(locator,wait=wait)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\nself = , locator = {'dynamic': False, 'name': '发布', 'page': '视频发布页', 'switch': None, ...}, is_need_displayed = True, wait = 5, is_raise = True\n\n def _find_element(self, locator, is_need_displayed=True,wait = 5,is_raise=True):\n \"\"\"查找单个元素,如果有多个返回第一个\n \n Args:\n locator: 定位器\n is_need_displayed: 是否需要定位的元素必须展示\n is_raise: 是否抛出异常\n \n Returns: 元素 ,没找到返回 None\n \n Raises: NotFoundElementError\n 未找到元素会抛 NotFoundElementError 异常\n \n \"\"\"\n \n waittime_count=Waittime_count(msg='[查找] 页面【{}】该元素【{}】等待时间:'.format(locator.get(\"page\"),locator.get(\"name\")))\n waittime_count.start()\n try:\n if is_need_displayed:\n WebDriverWait(self.driver, wait).until(\n lambda driver: self._get_element_by_type(driver, locator).is_displayed())\n else:\n WebDriverWait(self.driver, wait).until(\n lambda driver: self._get_element_by_type(driver, locator) is not None)\n \n waittime_count.end()\n return self._get_element_by_type(self.driver, locator)\n except Exception as e:\n \n if is_raise==True:\n log.error(\n \"【{}】页面中未能找到元素【{}】\\n locator: \\n {}\".format(locator.get(\"page\"), locator.get(\"name\"), locator))\n> raise NotFoundElementError\nE base.verify.NotFoundElementError\n\nbase/action.py:587: NotFoundElementError"}, "attachments": [{"name": "log", "source": "d250f3a8-fd22-49dd-a10f-97aaad63a8dc-attachment.txt", "type": "text/plain"}, {"name": "stdout", "source": "3169bc89-e5e3-409c-8f4c-e0900691703e-attachment.txt", "type": "text/plain"}, {"name": "stderr", "source": "8ada9ae0-65b8-43d7-88f9-68d5851714b3-attachment.txt", "type": "text/plain"}], "start": 1546833967879, "stop": 1546833975071, "uuid": "a1903318-27e1-451d-a652-4b1b792b37c2", "historyId": "61d0ec5868142760393bb75a0ddaae70", "fullName": "tests.test_vedio.test_videorelease.Test_videorelease#test_case1", "labels": [{"name": "parentSuite", "value": "tests.test_vedio"}, {"name": "suite", "value": "test_videorelease"}, {"name": "subSuite", "value": "Test_videorelease"}, {"name": "host", "value": "tangmaoheng-deMacBook-Air.local"}, {"name": "thread", "value": "14748-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "tests.test_vedio.test_videorelease"}]} -------------------------------------------------------------------------------- /report/xml/e6773643-77f7-4893-8324-8de181c0ef6c-result.json: -------------------------------------------------------------------------------- 1 | {"name": "test_case1", "status": "broken", "statusDetails": {"message": "UnboundLocalError: local variable 'Resolution' referenced before assignment", "trace": "> lambda: ihook(item=item, **kwds),\n when=when,\n )\n\n/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/flaky/flaky_pytest_plugin.py:273: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\nbase/conftest_android.py:58: in action\n element_action=ElementActions(driverenv)\nbase/utils.py:15: in getinstance\n instances[class_] = class_(*args, **kwargs)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\nself = , driver = \n\n def __init__(self, driver: webdriver.Remote):\n self.driver = driver\n self.env = EnvironmentAndroid()\n #通过driver.get_window_size()获取的分辨率会不准确,所以读取配置的Resolution\n self.Resolution =self.env.current_device.get('Resolution')\n \n> if Resolution==None:\nE UnboundLocalError: local variable 'Resolution' referenced before assignment\n\nbase/action.py:27: UnboundLocalError"}, "attachments": [{"name": "log", "source": "86139c2a-aea2-47d8-b30a-5eef2e73f365-attachment.txt", "type": "text/plain"}, {"name": "stdout", "source": "d843718e-d2d1-4fb8-a491-c8d73570195f-attachment.txt", "type": "text/plain"}, {"name": "stderr", "source": "0b80182a-5c2d-44fd-926e-b8970e982495-attachment.txt", "type": "text/plain"}], "uuid": "b4e756f8-126c-4094-b908-95c5d947a2e3", "historyId": "61d0ec5868142760393bb75a0ddaae70", "fullName": "tests.test_vedio.test_videorelease.Test_videorelease#test_case1", "labels": [{"name": "parentSuite", "value": "tests.test_vedio"}, {"name": "suite", "value": "test_videorelease"}, {"name": "subSuite", "value": "Test_videorelease"}, {"name": "host", "value": "tangmaoheng-deMacBook-Air.local"}, {"name": "thread", "value": "14497-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "tests.test_vedio.test_videorelease"}]} -------------------------------------------------------------------------------- /report/xml/e86819b3-9efe-4f9b-a8b3-5d4e53b10ddf-attachment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/e86819b3-9efe-4f9b-a8b3-5d4e53b10ddf-attachment.png -------------------------------------------------------------------------------- /report/xml/e9d5fee0-9a43-43d3-8f3c-2eaa8e473f48-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "21f00202-68f0-4e3d-a5c5-4e35721c0658", "children": ["b4e756f8-126c-4094-b908-95c5d947a2e3"], "befores": [{"name": "action", "status": "broken", "statusDetails": {"message": "UnboundLocalError: local variable 'Resolution' referenced before assignment\n", "trace": " File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pluggy/callers.py\", line 187, in _multicall\n res = hook_impl.function(*args)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 969, in pytest_fixture_setup\n result = call_fixture_func(fixturefunc, request, kwargs)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 824, in call_fixture_func\n res = next(it)\n File \"/Users/tmh/PycharmProjects/appauto/base/conftest_android.py\", line 58, in action\n element_action=ElementActions(driverenv)\n File \"/Users/tmh/PycharmProjects/appauto/base/utils.py\", line 15, in getinstance\n instances[class_] = class_(*args, **kwargs)\n File \"/Users/tmh/PycharmProjects/appauto/base/action.py\", line 27, in __init__\n if Resolution==None:\n"}, "start": 1546833843507, "stop": 1546833843507}], "start": 1546833843507, "stop": 1546833843722} -------------------------------------------------------------------------------- /report/xml/efe03640-0e8a-4bbb-8193-5e001ebcdd79-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "8ab86039-b647-469b-82a6-8c99ef75d164", "children": ["a1903318-27e1-451d-a652-4b1b792b37c2"], "befores": [{"name": "driverenv", "status": "passed", "start": 1546833922587, "stop": 1546833935128}], "start": 1546833922587, "stop": 1546833977193} -------------------------------------------------------------------------------- /report/xml/environment.properties: -------------------------------------------------------------------------------- 1 | #Mon Jan 07 14:42:24 CST 2019 2 | appium.app=/Users/tmh/PycharmProjects/appauto/data/apk/jumei.apk 3 | appium.appActivity=com.jm.android.jumei.home.activity.StartActivity 4 | appium.appPackage=com.jm.android.jumei 5 | appium.version=1.9.1 6 | appium.host=http\://localhost\:4723/wd/hub 7 | path.tests=/Users/tmh/PycharmProjects/appauto/tests 8 | path.report=/Users/tmh/PycharmProjects/appauto/report 9 | device1.deviceName=2425a80b 10 | device1.platformName=Android 11 | device1.platformVersion=8.1.0 12 | device1.appiumserver=http\://localhost\:4723/wd/hub 13 | device1.systemPort=8201 14 | platform.run=android 15 | -------------------------------------------------------------------------------- /report/xml/f096293f-0f79-49bc-a93d-6788cd87963e-attachment.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/report/xml/f096293f-0f79-49bc-a93d-6788cd87963e-attachment.txt -------------------------------------------------------------------------------- /report/xml/f16bad53-ac59-4ac7-b2a4-731d3329d142-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "3cf72c16-3807-499a-b93c-79fb7da590b1", "children": ["ae9916db-8cc6-4553-b951-b96b3d1ed3d8"], "befores": [{"name": "driverenv", "status": "broken", "statusDetails": {"message": "selenium.common.exceptions.InvalidArgumentException: Message: 'unicodeKeyboard' must be of type boolean\n\n", "trace": " File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pluggy/callers.py\", line 187, in _multicall\n res = hook_impl.function(*args)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 969, in pytest_fixture_setup\n result = call_fixture_func(fixturefunc, request, kwargs)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/fixtures.py\", line 828, in call_fixture_func\n res = fixturefunc(**kwargs)\n File \"/Users/tmh/PycharmProjects/appauto/base/conftest_android.py\", line 49, in driverenv\n driver = webdriver.Remote(host, capabilities)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/appium/webdriver/webdriver.py\", line 97, in __init__\n super(WebDriver, self).__init__(command_executor, desired_capabilities, browser_profile, proxy, keep_alive)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py\", line 157, in __init__\n self.start_session(capabilities, browser_profile)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/appium/webdriver/webdriver.py\", line 138, in start_session\n response = self.execute(RemoteCommand.NEW_SESSION, parameters)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py\", line 321, in execute\n self.error_handler.check_response(response)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py\", line 242, in check_response\n raise exception_class(message, screen, stacktrace)\n"}, "start": 1546833641256, "stop": 1546833641334}], "start": 1546833641256, "stop": 1546833641561} -------------------------------------------------------------------------------- /report/xml/f662782f-5a06-42dd-868f-3d0967c0be4a-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "75f060d7-cdd8-4077-b48d-20d1e1202af6", "children": ["dcd5be3e-4d73-4b38-b2be-d28593a64d8f"], "befores": [{"name": "suitinit", "status": "passed", "start": 1546842430359, "stop": 1546842463042}], "start": 1546842430359, "stop": 1546842472744} -------------------------------------------------------------------------------- /report/xml/fc6cff4e-2457-45a5-99e7-3437d611660b-result.json: -------------------------------------------------------------------------------- 1 | {"name": "test_case1", "status": "broken", "statusDetails": {"message": "base.verify.NotFoundElementError", "trace": "self = , locator = {'dynamic': False, 'name': '发布', 'page': '视频发布页', 'switch': None, ...}, is_need_displayed = True, wait = 5, is_raise = True\n\n def _find_element(self, locator, is_need_displayed=True,wait = 5,is_raise=True):\n \"\"\"查找单个元素,如果有多个返回第一个\n \n Args:\n locator: 定位器\n is_need_displayed: 是否需要定位的元素必须展示\n is_raise: 是否抛出异常\n \n Returns: 元素 ,没找到返回 None\n \n Raises: NotFoundElementError\n 未找到元素会抛 NotFoundElementError 异常\n \n \"\"\"\n \n waittime_count=Waittime_count(msg='[查找] 页面【{}】该元素【{}】等待时间:'.format(locator.get(\"page\"),locator.get(\"name\")))\n waittime_count.start()\n try:\n if is_need_displayed:\n WebDriverWait(self.driver, wait).until(\n> lambda driver: self._get_element_by_type(driver, locator).is_displayed())\n\nbase/action.py:575: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\nself = , method = . at 0x10b7746a8>\nmessage = ''\n\n def until(self, method, message=''):\n \"\"\"Calls the method provided with the driver as an argument until the \\\n return value is not False.\"\"\"\n screen = None\n stacktrace = None\n \n end_time = time.time() + self._timeout\n while True:\n try:\n value = method(self._driver)\n if value:\n return value\n except self._ignored_exceptions as exc:\n screen = getattr(exc, 'screen', None)\n stacktrace = getattr(exc, 'stacktrace', None)\n time.sleep(self._poll)\n if time.time() > end_time:\n break\n> raise TimeoutException(message, screen, stacktrace)\nE selenium.common.exceptions.TimeoutException: Message:\n\n/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/support/wait.py:80: TimeoutException\n\nDuring handling of the above exception, another exception occurred:\n\nself = , action = \n\n def test_case1(self,action):\n count=5\n action.click(p.特卖首页.发布)\n \n for index in range(count):\n> action.click(vp.视频发布页.视频发布)\n\ntests/test_vedio/test_videorelease.py:18: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\nbase/action.py:329: in click\n element = self._find_element(locator,wait=wait)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\nself = , locator = {'dynamic': False, 'name': '发布', 'page': '视频发布页', 'switch': None, ...}, is_need_displayed = True, wait = 5, is_raise = True\n\n def _find_element(self, locator, is_need_displayed=True,wait = 5,is_raise=True):\n \"\"\"查找单个元素,如果有多个返回第一个\n \n Args:\n locator: 定位器\n is_need_displayed: 是否需要定位的元素必须展示\n is_raise: 是否抛出异常\n \n Returns: 元素 ,没找到返回 None\n \n Raises: NotFoundElementError\n 未找到元素会抛 NotFoundElementError 异常\n \n \"\"\"\n \n waittime_count=Waittime_count(msg='[查找] 页面【{}】该元素【{}】等待时间:'.format(locator.get(\"page\"),locator.get(\"name\")))\n waittime_count.start()\n try:\n if is_need_displayed:\n WebDriverWait(self.driver, wait).until(\n lambda driver: self._get_element_by_type(driver, locator).is_displayed())\n else:\n WebDriverWait(self.driver, wait).until(\n lambda driver: self._get_element_by_type(driver, locator) is not None)\n \n waittime_count.end()\n return self._get_element_by_type(self.driver, locator)\n except Exception as e:\n \n if is_raise==True:\n log.error(\n \"【{}】页面中未能找到元素【{}】\\n locator: \\n {}\".format(locator.get(\"page\"), locator.get(\"name\"), locator))\n> raise NotFoundElementError\nE base.verify.NotFoundElementError\n\nbase/action.py:587: NotFoundElementError"}, "attachments": [{"name": "log", "source": "543b24cf-ea3b-4ecf-b1ba-f5e4eaebf854-attachment.txt", "type": "text/plain"}, {"name": "stdout", "source": "3502b925-0d38-4e4f-b528-038c9bc3cd66-attachment.txt", "type": "text/plain"}, {"name": "stderr", "source": "da44832c-0a1a-4e54-aab3-88269f1306ff-attachment.txt", "type": "text/plain"}], "start": 1546842463044, "stop": 1546842470808, "uuid": "dcd5be3e-4d73-4b38-b2be-d28593a64d8f", "historyId": "61d0ec5868142760393bb75a0ddaae70", "fullName": "tests.test_vedio.test_videorelease.Test_videorelease#test_case1", "labels": [{"name": "parentSuite", "value": "tests.test_vedio"}, {"name": "suite", "value": "test_videorelease"}, {"name": "subSuite", "value": "Test_videorelease"}, {"name": "host", "value": "tangmaoheng-deMacBook-Air.local"}, {"name": "thread", "value": "15102-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "tests.test_vedio.test_videorelease"}]} -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | selenium==3.14.1 2 | Appium-Python-Client 3 | PyYAML 4 | pytest 5 | allure-pytest 6 | flaky 7 | pytest-sugar 8 | jprops -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | import pytest,sys 6 | from multiprocessing import Pool 7 | from base.run import Run 8 | from base.utils import log,Conf 9 | from base.shell import Shell 10 | 11 | 12 | """ 13 | run all case: 14 | python3 run.py 15 | 16 | run one module case: 17 | python3 run.py test/test_demo.py 18 | 19 | run case with key word: 20 | python3 run.py -k 21 | run class case: 22 | python3 run.py test/test_demo.py::Test_demo 23 | run class::method case: 24 | python3 run.py test/test_demo.py::Test_demo::test_home 25 | """ 26 | 27 | if __name__ == '__main__': 28 | 29 | 30 | platform=Conf().androidname #android or ios 31 | 32 | run=Run(platform) 33 | 34 | 35 | #获取命令行参数中的用例执行作用域 36 | run.exec(sys.argv[1:]) 37 | 38 | 39 | run.generate_report() 40 | 41 | 42 | -------------------------------------------------------------------------------- /tests/test_suit2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/tests/test_suit2/__init__.py -------------------------------------------------------------------------------- /tests/test_suit2/conftest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import pytest 4 | 5 | from base.utils import Conf 6 | from lib.pages.set import ProductPages as p, UserCenterPage as up 7 | from lib.reuse_business import base_business 8 | 9 | conf = Conf() 10 | 11 | if conf.platform == conf.androidname: 12 | from base.conftest_android import * 13 | elif conf.platform == conf.iosname: 14 | from base.conftest_ios import * 15 | 16 | 17 | #运行时通过执行的配置的平台决定导入的模块 18 | #导入base.conftest里的pytest上下文环境函数:driverenv、action(ElementActions的实例)、caselog 19 | #pytest框架运行原理:先运行test文件夹下面的conftest.py,然后才运行带test开头的py文件 20 | 21 | @pytest.fixture('package',autouse=True) 22 | def suitinit(action): 23 | # p.特卖首页.home(action) 24 | p.特卖首页.pageinto(action) 25 | # base_business.set_appenv(action) 26 | 27 | -------------------------------------------------------------------------------- /tests/test_suit2/test_demo2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from base.action import ElementActions 3 | from lib.pages.set import ProductPages as p 4 | from base.verify import NotFoundTextError 5 | from base.utils import log 6 | 7 | #测试用例demo,pytest框架自动加载执行 8 | 9 | 10 | 11 | class Test_demo(): 12 | 13 | 14 | 15 | 16 | def test_home(self, action: ElementActions): 17 | 18 | # up.登录页.login(action,'13550234762','tmhrush2233') 19 | 20 | 21 | action.click(p.特卖首页.搜索输入框) 22 | 23 | #因为调用action的大部分公用方法是返回self,所以可以一条语句执行多次不同方法 24 | action.text(p.分类列表搜索页.搜索输入框,"口红")\ 25 | .click(p.分类列表搜索页.搜索按钮) 26 | 27 | action.click(p.搜索后列表页.第一个商品项) 28 | 29 | #循环下拉,检查是否有对应关键字,找到后终止 30 | for count in range(20): 31 | if action.swip_down().is_text_displayed("商品参数"): 32 | break 33 | #没有对应关键字抛出错误 34 | if action.is_text_displayed("口红") ==False: 35 | raise NotFoundTextError 36 | 37 | action.sleep(1) 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /tests/test_usercenter/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/tests/test_usercenter/__init__.py -------------------------------------------------------------------------------- /tests/test_usercenter/conftest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from base.utils import Conf 4 | from lib.pages.set import ProductPages as p, UserCenterPage as up 5 | from lib.reuse_business import base_business 6 | 7 | 8 | conf=Conf() 9 | 10 | 11 | if conf.platform==conf.androidname: 12 | from base.conftest_android import * 13 | elif conf.platform==conf.iosname: 14 | from base.conftest_ios import * 15 | 16 | 17 | @pytest.fixture('package',autouse=True) 18 | def suitinit(action): 19 | # p.特卖首页.home(action) 20 | p.特卖首页.pageinto(action) 21 | # base_business.set_appenv(action) 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/test_usercenter/test_returngoods.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | from base.action import ElementActions 4 | from lib.pages.set import ProductPages as p, UserPages as up,BuyPages as bp 5 | from base.verify import Validator,NotFoundElementError 6 | from lib.reuse_business import base_business,shopping_business 7 | from base.utils import log 8 | from flaky import flaky 9 | 10 | class Test_productbrowse(): 11 | 12 | def clear_browsenumber(self,action:ElementActions): 13 | action.click(up.用户中心.浏览记录) 14 | if action.is_element_exist(up.浏览记录.编辑): 15 | action.click(up.浏览记录.编辑) 16 | product_eles=action.find_ele(up.浏览记录.编辑页浏览商品选择按钮,is_Multiple=True) 17 | for product_ele in product_eles: 18 | action.click_ele(product_ele) 19 | action.click(up.浏览记录.删除).click(up.浏览记录.删除弹窗确定按钮) 20 | 21 | log.info('当前浏览记录为空~') 22 | 23 | 24 | 25 | def get_browsenumber(self,action:ElementActions): 26 | tmpele = action.find_ele(up.用户中心.用户中心列表) 27 | tmpele2 = action.find_ele_child(tmpele, up.用户中心.用户中心列表_列表1) 28 | browsenumberele = action.find_ele_child(tmpele2, up.用户中心.用户中心列表_列表1_相关数量,is_Multiple=True)[2] 29 | browsenumber = action.get_text_ele(browsenumberele) 30 | 31 | log.info('当前浏览记录值为{}'.format(browsenumber)) 32 | 33 | return browsenumber 34 | 35 | #已登陆时生成浏览记录 36 | @flaky() 37 | def test_case1(self,action): 38 | 39 | base_business.login(action) 40 | 41 | self.clear_browsenumber(action) 42 | productname=shopping_business.browseproduct(action,key='爽肤水') 43 | 44 | up.用户中心.pageinto(action) 45 | new_browsenumber=int(self.get_browsenumber(action)) 46 | 47 | logmsg="断言成功:浏览记录正常+1" 48 | errormsg="断言失败:当前new_browsenumber={}".format(new_browsenumber) 49 | Validator.assert_eq(1,new_browsenumber,errormsg,logmsg) 50 | 51 | #访问浏览记录页 52 | action.click(up.用户中心.浏览记录) 53 | 54 | map={ 'value':productname} 55 | browseproduct_locator=up.浏览记录.newlocator(up.浏览记录.当前浏览商品,map) 56 | action.get_img('当天的浏览记录') 57 | Validator.assert_true(action.is_element_exist(browseproduct_locator),'断言失败:没找到对应的浏览商品名') 58 | 59 | 60 | 61 | 62 | 63 | 64 | class Test_favourite(): 65 | 66 | 67 | 68 | #收藏商品,然后再删除对应的收藏 69 | def test_case1(self,action): 70 | base_business.login(action) 71 | productname=shopping_business.browseproduct(action,key='爽肤水') 72 | action.click(p.商品详情页.收藏按钮) 73 | 74 | toast=action.is_toast_show('收藏成功') 75 | Validator.assert_true(toast,"断言失败: 没收藏成功的提示") 76 | 77 | up.用户中心.pageinto(action) 78 | action.click(up.用户中心.收藏商品) 79 | 80 | product_locator=up.收藏页.newlocator(up.收藏页.当前收藏商品, 'value', productname) 81 | action.get_img('收藏商品列表') 82 | Validator.assert_true(action.is_element_exist(product_locator),'断言失败: 没找到对应收藏的商品') 83 | 84 | #删除收藏 85 | action.long_press(product_locator,time=4000) 86 | action.click(up.收藏页.删除收藏) 87 | toast = action.is_toast_show('删除成功') 88 | Validator.assert_true(toast, "断言失败: 没删除成功的提示") 89 | 90 | 91 | 92 | class Test_debug(): 93 | 94 | def test_case1(self,action): 95 | 96 | 97 | up.用户中心.pageinto(action) 98 | action.click(up.用户中心.查看全部订单) 99 | action.get_img('我的订单') 100 | 101 | map={'value':".//android.widget.TextView[@text='爱的']"} 102 | productname_locator=bp.我的订单页.newlocator(bp.我的订单页.订单商品名,map) 103 | 104 | eles=action.find_ele(productname_locator,is_Multiple=True,wait=5) 105 | log.info(eles) 106 | 107 | product_ele=action.find_ele_parent(bp.我的订单页.订单商品项s,productname_locator,wait=4) 108 | log.info(product_ele) 109 | 110 | price_ele=action.find_ele_child_byelement(product_ele,bp.我的订单页.订单商品单价格s) 111 | log.info(action.get_text_ele(price_ele)) 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /tests/test_vedio/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushtang/py_appauto/e53e2cb7c1f4816acce9013f13028d7a5d9febbc/tests/test_vedio/__init__.py -------------------------------------------------------------------------------- /tests/test_vedio/conftest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from base.utils import Conf 4 | from lib.pages.set import ProductPages as p, UserCenterPage as up 5 | from lib.reuse_business import base_business 6 | 7 | 8 | conf=Conf() 9 | 10 | 11 | if conf.platform==conf.androidname: 12 | from base.conftest_android import * 13 | elif conf.platform==conf.iosname: 14 | from base.conftest_ios import * 15 | 16 | 17 | @pytest.fixture('package',autouse=True) 18 | def suitinit(action): 19 | # p.特卖首页.home(action) 20 | # base_business.set_appenv(action) 21 | # p.特卖首页.pageinto(action) 22 | base_business.login(action,'user1') 23 | # action.back_press() 24 | pass 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /tests/test_vedio/test_videorelease.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | from base.action import ElementActions 4 | from lib.pages.set import ProductPages as p, UserPages as up,VedioPages as vp 5 | from base.verify import Validator,NotFoundElementError 6 | from base.utils import log 7 | from flaky import flaky 8 | 9 | 10 | 11 | class Test_videorelease(): 12 | 13 | def test_case1(self,action): 14 | count=5 15 | action.click(p.特卖首页.发布) 16 | 17 | for index in range(count): 18 | action.click(p.特卖首页.发布_上传视频) 19 | videoele=action.find_ele(vp.视频发布页.视频选择,is_Multiple=True)[0] 20 | action.click_ele(videoele) 21 | 22 | action.click(vp.视频发布页.视频选择后下一步).click(vp.视频发布页.视频处理后下一步) 23 | 24 | action.sleep(8).click(vp.视频发布页.视频发布,wait=15) 25 | 26 | result=action.is_toast_show('视频发布成功',wait=20) 27 | log.info('result: {}'.format(result)) 28 | action.get_img('上传后截图') 29 | 30 | action.back_press() 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | --------------------------------------------------------------------------------