parent
254a708932
commit
cc7e75dfc7
|
@ -170,7 +170,7 @@ class BaseWidget(Src):
|
|||
|
||||
公共方法库里面每个应用都是一个单独的 `py` 文件,相互之间是独立的,每个 `py` 文件里面是该应用的方法类,比如:最常用的方法类 `dde_desktop_public_widget.py`
|
||||
|
||||
```python title="dde_desktop_public_widget.py"
|
||||
```python title="dde_desktop_public_widget.py" hl_lines="3 13"
|
||||
from src import Src
|
||||
|
||||
class _DdeDesktopPublicBaseWidget(Src):
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
```shell
|
||||
# =================================================
|
||||
# Author : mikigo
|
||||
# Time : 2022/3/16
|
||||
# version :1.0
|
||||
# =================================================
|
||||
```
|
||||
|
||||
|
@ -19,12 +17,13 @@ AT 应用库改造是基于自动化测试基础框架进行用例方法和业
|
|||
|
||||
整体仍然遵循 PO 设计理念,根据业务需要,将文管业务层进行 3 层划分:
|
||||
|
||||
![](https://pic.imgdb.cn/item/64f054c3661c6c8e54ff47db.png)
|
||||
???+ note "应用库架构图(文件管理器)"
|
||||
![](https://pic.imgdb.cn/item/64f054c3661c6c8e54ff47db.png)
|
||||
|
||||
### 2、目录结构
|
||||
|
||||
```shell
|
||||
autotest-dde-file-manager # 应用仓库
|
||||
autotest_dde_file_manager # 应用仓库
|
||||
├── case # 用例
|
||||
│ ├── assert_res # 断言的图片资源目录
|
||||
│ ├── test_xxx_001.py
|
||||
|
@ -51,72 +50,65 @@ autotest-dde-file-manager # 应用仓库
|
|||
|
||||
## 三、详细方案
|
||||
|
||||
### 1、基类
|
||||
### 1、基类(base_widget.py)
|
||||
|
||||
- 继承核心层的各个模块类。
|
||||
- 抽取操作层的一些基础方法。
|
||||
- 元素定位操作的一些公共方法。
|
||||
- 路径组装方法。
|
||||
- 一些**业务层**相关的变量、常量、shell命令、坐标。
|
||||
|
||||
方法基类的写法:
|
||||
|
||||
```python
|
||||
from src import Src
|
||||
|
||||
class BaseWidget(Src):
|
||||
- 继承核心层(src.Src);
|
||||
```python
|
||||
from src import Src
|
||||
|
||||
class BaseWidget(Src):
|
||||
"""方法基类"""
|
||||
APP_NAME = "dde-file-manager"
|
||||
DESC = "/usr/bin/dde-file-manager"
|
||||
|
||||
def __init__(self, number=-1):
|
||||
Src.__init__(self, APP_NAME=self.APP_NAME, DESC=self.DESC, number=number)
|
||||
```
|
||||
|
||||
APP_NAME = "dde-file-manager"
|
||||
DESC = "/usr/bin/dde-file-manager"
|
||||
|
||||
def __init__(self, number=-1):
|
||||
Src.__init__(self, APP_NAME=self.APP_NAME, DESC=self.DESC, number=number)
|
||||
```
|
||||
- 抽取操作层的一些基础方法;
|
||||
- 元素定位操作的一些公共方法;
|
||||
- 路径组装方法;
|
||||
- 一些**业务层**相关的变量、常量、shell命令、坐标;
|
||||
|
||||
### 2、操作层
|
||||
|
||||
- 模块划分
|
||||
|
||||
按照文件管理器的界面区域划分为:`TitleWidget` 、`RightViewWidget`、`LeftViewWidget` 、`PopWidget`
|
||||
按照文件管理器的界面区域划分为:==TitleWidget 、RightViewWidget、LeftViewWidget 、PopWidget== ;
|
||||
|
||||
文管主界面分为三个区域:标题栏、右边视图区域、左边视图区域
|
||||
文管界面分为四个区域:==标题栏、右边视图区域、左边视图区域、弹窗[^1]==;
|
||||
|
||||
弹窗:设置界面弹窗、保险箱弹窗、删除确认弹窗、及各种网络弹窗
|
||||
[^1]: 设置界面弹窗、保险箱弹窗、删除确认弹窗、及各种网络弹窗.
|
||||
|
||||
右键菜单:暂时不考虑为单独的模块,考虑以图像识别的定位方案做成公共库。
|
||||
???+ note "主界面区域划分"
|
||||
![](https://pic.imgdb.cn/item/64f054c3661c6c8e54ff4806.png)
|
||||
???+ note "弹窗区域"
|
||||
![](https://pic.imgdb.cn/item/64f054c8661c6c8e54ff4d1b.png)
|
||||
|
||||
![](https://pic.imgdb.cn/item/64f054c3661c6c8e54ff4806.png)
|
||||
|
||||
![](https://pic.imgdb.cn/item/64f054c8661c6c8e54ff4d1b.png)
|
||||
|
||||
![](https://pic.imgdb.cn/item/64f054c9661c6c8e54ff4d5a.png)
|
||||
|
||||
- 各个模块只继承基类
|
||||
|
||||
```python
|
||||
from apps.dde_file_manager.widget import BaseWidget # dde_file_manager 为仓库名称
|
||||
```python title="标题栏" hl_lines="1 3"
|
||||
from apps.autotest_dde_file_manager.widget import BaseWidget
|
||||
|
||||
class TitleWidget(BaseWidget):
|
||||
class TitleWidget(BaseWidget):
|
||||
"""标题栏方法类"""
|
||||
|
||||
|
||||
def click_xxx_in_title_by_ui(self):
|
||||
# self.dog.find_element_by_attr("xxxx").click()
|
||||
self.click(*self.ui.btn_center("xxx"))
|
||||
```
|
||||
```
|
||||
|
||||
- 构造函数里面不构造对象,可以初始化一些变量。
|
||||
|
||||
- 不同的定位方案调用不同的定位工具对象。
|
||||
|
||||
```python
|
||||
self.dog
|
||||
self.ui
|
||||
self.d_bus
|
||||
```
|
||||
```python
|
||||
self.dog
|
||||
self.ui
|
||||
```
|
||||
|
||||
- 方法编写
|
||||
|
||||
- 动作开头,注意是动词
|
||||
- 动作开头,注意是动词
|
||||
|
||||
```python
|
||||
click
|
||||
|
@ -125,24 +117,23 @@ class BaseWidget(Src):
|
|||
get
|
||||
make
|
||||
```
|
||||
|
||||
- 元素对象名称
|
||||
|
||||
- 界面元素直接与元素名称相同,没有名称的就取一个好听易懂的名字。
|
||||
|
||||
- **加上类的关键词**
|
||||
|
||||
- 避免方法重名,同时可以标记区域。
|
||||
|
||||
- 标定操作方法
|
||||
|
||||
```python
|
||||
by_ui
|
||||
by_attr
|
||||
by_mk
|
||||
by_img
|
||||
```
|
||||
|
||||
- 元素对象名称
|
||||
|
||||
界面元素直接与元素名称相同,没有名称的就取一个好听易懂的名字。
|
||||
|
||||
- 加上类的关键词
|
||||
|
||||
避免方法重名,同时可以标记区域。
|
||||
|
||||
- 标定操作方法
|
||||
|
||||
```python
|
||||
by_ui
|
||||
by_attr
|
||||
by_mk
|
||||
by_img
|
||||
```
|
||||
|
||||
### 3、应用层
|
||||
|
||||
|
@ -150,42 +141,47 @@ class BaseWidget(Src):
|
|||
|
||||
- 仅仅用于用例中导入方便,不做其他事情。
|
||||
|
||||
```python
|
||||
class DfmWidget(TitleWidget, RightViewWidget, LeftViewWidget, PopWidget):
|
||||
pass
|
||||
```
|
||||
```python
|
||||
class DfmWidget(TitleWidget, RightViewWidget, LeftViewWidget, PopWidget):
|
||||
pass
|
||||
```
|
||||
|
||||
- `DfmAssert` 直接在用例里面继承,方便使用断言语句。
|
||||
|
||||
```python
|
||||
from apps.dde_file_manager.widget.dfm_widget import DfmWidget
|
||||
from public.assert import Assert
|
||||
```python hl_lines="2 4 7"
|
||||
from apps.dde_file_manager.widget.dfm_widget import DfmWidget
|
||||
from public.assert import Assert
|
||||
|
||||
class DfmAssert(Assert):
|
||||
|
||||
def assert_file_exists_in_desktop(self, file_name):
|
||||
self.assert_file_exists(f"~/Desktop{file_name}")
|
||||
...
|
||||
DfmWidget().get_file_in_desktop()
|
||||
```
|
||||
class DfmAssert(Assert):
|
||||
|
||||
def assert_file_exists_in_desktop(self, file_name):
|
||||
self.assert_file_exists(f"~/Desktop{file_name}")
|
||||
...
|
||||
DfmWidget().get_file_in_desktop()
|
||||
```
|
||||
|
||||
- 用例里面直接继承,方便在用例里面使用 self 进行断言,更符合断言的使用习惯,用例逻辑上更清楚。
|
||||
|
||||
```python
|
||||
class BaseCase(DfmAssert):
|
||||
pass
|
||||
|
||||
class TestFileManager(BaseCase):
|
||||
def test_xxx_001(self):
|
||||
self.assert_file_exists_in_desktop("xxx")
|
||||
```
|
||||
```python hl_lines="1 3" title="case/base_case.py"
|
||||
from public.assert import Assert
|
||||
|
||||
class BaseCase(DfmAssert):
|
||||
pass
|
||||
```
|
||||
|
||||
```python hl_lines="1 3 5" title="case/test_xxx_001.py"
|
||||
from apps.autotest_dde_file_manager.case import BaseCase
|
||||
|
||||
class TestFileManager(BaseCase):
|
||||
def test_xxx_001(self):
|
||||
self.assert_file_exists_in_desktop("xxx")
|
||||
```
|
||||
|
||||
### 4、逻辑举例
|
||||
|
||||
用例代码调用逻辑举例:
|
||||
|
||||
```python
|
||||
# BaseWidget
|
||||
```python title="widget/base_widget.py"
|
||||
class BaseWidget(Src):
|
||||
"""方法基类"""
|
||||
APP_NAME = "dde-file-manager"
|
||||
|
@ -193,10 +189,11 @@ class BaseWidget(Src):
|
|||
|
||||
def __init__(self, number=-1):
|
||||
Src.__init__(self, APP_NAME=self.APP_NAME, DESC=self.DESC, number=number)
|
||||
```
|
||||
|
||||
```python title="widget/title_widget.py"
|
||||
from apps.autotest_dde_file_manager.widget import BaseWidget
|
||||
|
||||
# =============================================
|
||||
# TitleWidget
|
||||
class TitleWidget(BaseWidget):
|
||||
|
||||
def __init__(self, nubmer=-1):
|
||||
|
@ -205,9 +202,11 @@ class TitleWidget(BaseWidget):
|
|||
def click_xxx_title_by_ui(self):
|
||||
print(self.dog.app_name)
|
||||
self.ui.print_number()
|
||||
```
|
||||
|
||||
```python title="widget/right_view_widget.py"
|
||||
from apps.autotest_dde_file_manager.widget import BaseWidget
|
||||
|
||||
# RightViewWidget
|
||||
class RightViewWidget(BaseWidget):
|
||||
|
||||
def __init__(self, nubmer=-1):
|
||||
|
@ -216,30 +215,35 @@ class RightViewWidget(BaseWidget):
|
|||
def click_xxx_right_by_ui(self):
|
||||
print(self.dog.app_name)
|
||||
self.ui.print_number()
|
||||
```
|
||||
|
||||
```python title="widget/dfm_widget.py"
|
||||
from apps.autotest_dde_file_manager.widget import TitleWidget
|
||||
from apps.autotest_dde_file_manager.widget import RightViewWidget
|
||||
|
||||
# =============================================
|
||||
# 出口 DfmWidget
|
||||
class DfmWidget(TitleWidget, RightViewWidget):
|
||||
pass
|
||||
```
|
||||
|
||||
```python title="case/test_xxx_002.py"
|
||||
from apps.dde_file_manager.widget import DfmWidget
|
||||
from apps.autotest_dde_file_manager.case import BaseCase
|
||||
|
||||
# =============================================
|
||||
# in case
|
||||
from apps.dde_file_manager.widget.dfm_widget import DfmWidget
|
||||
|
||||
dfm = DfmWidget()
|
||||
dfm.click_xxx_title_by_ui()
|
||||
dfm.click_xxx_right_by_ui()
|
||||
dfm.dog.print_desc()
|
||||
dfm.ui.print_number()
|
||||
class TestDdeFileManager(BaseCase):
|
||||
|
||||
def test_xxx_002(self):
|
||||
dfm = DfmWidget()
|
||||
dfm.click_xxx_title_by_ui()
|
||||
dfm.click_xxx_right_by_ui()
|
||||
dfm.dog.print_desc()
|
||||
dfm.ui.print_number()
|
||||
```
|
||||
|
||||
## 四、工程改造实施步骤
|
||||
|
||||
### 1、工程代码拉取
|
||||
### 1、基础框架代码拉取
|
||||
|
||||
1.1. 将自动化基础框架的功能拉到本地 `Autotest Basic Frame` :https://gerrit.uniontech.com/admin/repos/autotest-basic-frame
|
||||
1.1. 将自动化基础框架的功能拉到本地(参考《快速开始》章节)
|
||||
|
||||
1.2. 将应用库代码拉到基础框架下 `apps` 目录下,应用库的仓库命名应该是长这样的 `autotest_deepin_xxx`。
|
||||
|
||||
|
@ -261,7 +265,7 @@ dfm.ui.print_number()
|
|||
|
||||
在 `BaseWidget` 里面把该写的都写好,你可以参考上面的设计理念来写。
|
||||
|
||||
如果你嫌麻烦,你可以参考文管的实际工程代码 `autotest_dde_file_manager` : https://gerrit.uniontech.com/admin/repos/autotest_dde_file_manager 。
|
||||
如果你嫌麻烦,你可以参考文件管理器的实际工程代码 `autotest_dde_file_manager` : [https://gerrit.uniontech.com/admin/repos/autotest_dde_file_manager](https://gerrit.uniontech.com/admin/repos/autotest_dde_file_manager )
|
||||
|
||||
3.2. 操作层
|
||||
|
||||
|
|
466
docs/AT开发规范.md
466
docs/AT开发规范.md
|
@ -16,7 +16,7 @@ AT 开发规范是根据自动化测试运行多年以来,遇到问题解决
|
|||
|
||||
基础框架会根据自身的功能开发进行版本迭代发布,==基础框架不与某个应用版本绑定==;
|
||||
|
||||
但是,==应用库会依赖于基础框架的版本==。因此,我们建议在==应用库==目录下保存一个文本文件用于记录所依赖的基础框架版本,类似于开发应用的 `debian/control` 文件的功能,为了保持统一,这个文件就命名为 `control`,放在应用库根目录下。
|
||||
但是,==应用库会依赖于基础框架的版本==。因此,我们建议在 ==应用库== 目录下保存一个文本文件用于记录所依赖的基础框架版本,类似于开发应用的 `debian/control` 文件的功能,为了保持统一,这个文件就命名为 `control`,放在应用库根目录下。
|
||||
|
||||
## 2. 命名规范
|
||||
|
||||
|
@ -98,73 +98,146 @@ AT 开发规范是根据自动化测试运行多年以来,遇到问题解决
|
|||
- 不建议使用 `Xunit` 的写法,统一采用 `Pytest` `fixture` 的写法。
|
||||
- 应用内 `fixture` 谨慎使用 `autouse=True` ,非必要的情况下非常不建议使用这个参数。
|
||||
- 调用 `fixture` 不能使用 `@pytest.mark.usefixture()`,使用直接在用例里面传入函数对象。
|
||||
- 建议在一个 `conftest.py` 里面去写,一个应用也尽量维护一个 `conftest.py `文件。
|
||||
- 建议在一个 `conftest.py` 里面去写 `fixture`,一个应用也尽量维护一个 `conftest.py `文件。
|
||||
- `fixture` 也需要写功能说明,函数名称要有具体含义。
|
||||
|
||||
## 4. 方法编写规范
|
||||
## 4. 方法编写&调用规范
|
||||
|
||||
- 方法类型使用逻辑:
|
||||
### 4.1. 方法编写
|
||||
|
||||
```python
|
||||
if 没有用到实例对象:
|
||||
if 没有用到类对象:
|
||||
写静态方法,函数前加 @staticmethod
|
||||
- ==写方法的时候注意方法归属;==
|
||||
|
||||
比如文件管理器的界面区域划分为:`TitleWidget` 、`RightViewWidget`、`LeftViewWidget` 、`PopWidget`,方法是在哪个区域操作的,就写在哪个类里面。
|
||||
|
||||
举例:
|
||||
|
||||
```python hl_lines="3"
|
||||
from apps.autotest_dde_file_manager.widget import BaseWidget
|
||||
|
||||
class TitleWidget(BaseWidget):
|
||||
"""标题栏方法类"""
|
||||
|
||||
def click_xxx_in_title_by_ui(self):
|
||||
"""点击标题栏xxx"""
|
||||
# self.dog.find_element_by_attr("xxxx").click()
|
||||
self.click(*self.ui.btn_center("xxx"))
|
||||
```
|
||||
|
||||
- ==动作开头,注意是动词;==
|
||||
|
||||
```asciiarmor
|
||||
click
|
||||
double_click
|
||||
right_click
|
||||
get
|
||||
make
|
||||
```
|
||||
|
||||
- ==元素对象名称;==
|
||||
|
||||
界面元素直接与元素名称相同,没有名称的就取一个好听易懂的名字。
|
||||
|
||||
- ==加上类的关键词;==
|
||||
|
||||
避免方法重名,同时可以标记区域。
|
||||
|
||||
- ==标定操作方法类型;==
|
||||
|
||||
```asciiarmor
|
||||
by_ui
|
||||
by_attr
|
||||
by_mk
|
||||
by_img
|
||||
```
|
||||
|
||||
- ==正确使用方法类型;==
|
||||
|
||||
```python title="方法类型使用逻辑"
|
||||
if 没有用到实例对象:
|
||||
if 没有用到类对象:
|
||||
写静态方法,函数前加 @staticmethod
|
||||
else:
|
||||
写类方法,函数前加 @classmethod
|
||||
else:
|
||||
写类方法,函数前加 @classmethod
|
||||
else:
|
||||
直接写实例方法
|
||||
```
|
||||
```
|
||||
|
||||
举例:
|
||||
举例:
|
||||
|
||||
```python hl_lines="2-3 6-7 10-11"
|
||||
class TitleWidget:
|
||||
|
||||
```python
|
||||
class TitleWidget:
|
||||
|
||||
def click_xxx_by_ui(self):
|
||||
pass
|
||||
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def click_xxx_by_ui():
|
||||
pass
|
||||
|
||||
|
||||
@classmethod
|
||||
def click_xxx_by_ui(cls):
|
||||
pass
|
||||
|
||||
```
|
||||
|
||||
- 函数名称不出现数字,需要表示数量的用单词表示。
|
||||
|
||||
- 函数功能注释。
|
||||
```
|
||||
|
||||
- 没有参数,没有返回
|
||||
- 函数名称尽量不出现数字,需要表示数量的用单词表示。
|
||||
|
||||
```python
|
||||
"""点击某个元素"""
|
||||
```
|
||||
- ==函数功能注释;==
|
||||
|
||||
- 有参数,没有返回
|
||||
- 没有参数,没有返回,直接写函数功能说明;
|
||||
|
||||
```python
|
||||
"""点击某个元素
|
||||
arg1:xxx
|
||||
arg2:xxx
|
||||
"""
|
||||
```
|
||||
```python
|
||||
"""点击某个元素"""
|
||||
```
|
||||
|
||||
- 有参数,有返回
|
||||
- 有参数,没有返回,需要写各参数说明;
|
||||
|
||||
```python
|
||||
"""点击某个元素
|
||||
arg1:xxx
|
||||
arg1:xxx
|
||||
return: xxx
|
||||
"""
|
||||
```
|
||||
```python
|
||||
"""点击某个元素
|
||||
arg1:xxx
|
||||
arg2:xxx
|
||||
"""
|
||||
```
|
||||
|
||||
用 `Pycharm` 的注释模板也可以,只要体现了参数的类型和返回就行了。
|
||||
- 有参数,有返回,需要写返回值说明;
|
||||
|
||||
- 暂不要求写类型注解。
|
||||
```python
|
||||
"""点击某个元素
|
||||
arg1:xxx
|
||||
arg1:xxx
|
||||
return: xxx
|
||||
"""
|
||||
```
|
||||
|
||||
用 `Pycharm` 的注释模板也可以,只要体现了参数的类型和返回就行了。
|
||||
|
||||
- 暂不要求写类型注解。
|
||||
|
||||
### 4.2. 方法调用
|
||||
|
||||
在用例中调用方法,通过该应用唯一的出口进行调用,比如文件管理器的统一出口类:
|
||||
|
||||
```python hl_lines="1"
|
||||
class DfmWidget(TitleWidget, RightViewWidget, LeftViewWidget, PopWidget):
|
||||
pass
|
||||
```
|
||||
|
||||
在用例里面只需要导入这一个类即可;
|
||||
|
||||
```python hl_lines="1 9"
|
||||
from apps.autotest_dde_file_manager.widget import DfmWidget
|
||||
from apps.autotest_dde_file_manager.case.base_case import BaseCase
|
||||
|
||||
class TestDdeFileManager(BaseCase):
|
||||
"""文件管理器用例"""
|
||||
|
||||
def test_xxx_001(self):
|
||||
"""xxx"""
|
||||
dfm = DfmWidget()
|
||||
dfm.click_xxx_by_attr()
|
||||
```
|
||||
|
||||
==尽量不要在用例中单独去调用 TitleWidget 、RightViewWidget、LeftViewWidget 、PopWidget 这些类==,否则后期用例会变得不好维护;
|
||||
|
||||
## 5. 用例编写规范
|
||||
|
||||
|
@ -172,7 +245,7 @@ AT 开发规范是根据自动化测试运行多年以来,遇到问题解决
|
|||
|
||||
所有用例都应该基于类去写:
|
||||
|
||||
```python
|
||||
```python hl_lines="1"
|
||||
class TestMusic(BaseCase):
|
||||
"""音乐用例"""
|
||||
|
||||
|
@ -190,7 +263,7 @@ class TestMusic(BaseCase):
|
|||
|
||||
- ==一个类里面可以有多个用例函数==,这取决这条用例有多少个测试点:
|
||||
|
||||
```python title="test_music_679537.py"
|
||||
```python title="test_music_679537.py" hl_lines="4 7 10"
|
||||
class TestMusic(BaseCase):
|
||||
"""音乐用例"""
|
||||
|
||||
|
@ -204,8 +277,6 @@ class TestMusic(BaseCase):
|
|||
"""桌面启动音乐"""
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 5.2. 用例函数规范
|
||||
|
||||
- 用例函数以 test 开头,遵循蛇形命名规范,中间为用例的模块名称,后面加用例 ID,最后加测试点序号,即:
|
||||
|
@ -216,9 +287,9 @@ class TestMusic(BaseCase):
|
|||
|
||||
比如:`test_music_679537_1`,`index` 从 1 开始。
|
||||
|
||||
- ==函数功能说明== 里面写用例标题,==直接复制 PMS 上用例标题即可==,注意用 ==三对双引号==;
|
||||
- ==函数功能说明里面写用例标题,直接复制 PMS 上用例标题即可,注意用三对双引号==;
|
||||
|
||||
- ==复制 `PMS` 用例步骤==
|
||||
- ==复制 PMS 用例步骤==
|
||||
|
||||
直接将 `PMS` 上用例步骤和预期复制进来,然后进行批量注释( ++ctrl+"/"++ ),在注释的基础上去写用例脚本会更加方便全面,也比你自己写注释更节约时间:
|
||||
|
||||
|
@ -228,12 +299,12 @@ class TestMusic(BaseCase):
|
|||
|
||||
直接选中用例内容,复制下来,然后粘贴到自动化用例脚本中:
|
||||
|
||||
```python title="test_music_679537.py"
|
||||
```python title="test_music_679537.py" hl_lines="7-12"
|
||||
class TestMusic(BaseCase):
|
||||
"""音乐用例"""
|
||||
|
||||
def test_music_679537(self):
|
||||
"""演唱者-平铺视图下进入演唱者详情页"""
|
||||
"""演唱者-平铺视图下进入演唱者详情页""" <-- 从PMS上复制的用例标题
|
||||
|
||||
# 1
|
||||
# 点击右上角的【平铺视图】按钮
|
||||
|
@ -243,7 +314,7 @@ class TestMusic(BaseCase):
|
|||
# 进入演唱者详情页面
|
||||
```
|
||||
|
||||
上例中井号注释部分就是直接从 `PMS` 上复制过来的,在此基础上写用例:
|
||||
上例中井号(#)注释部分就是直接从 `PMS` 上复制过来的,在此基础上写用例:
|
||||
|
||||
```python title="test_music_679537.py"
|
||||
class TestMusic(BaseCase):
|
||||
|
@ -271,61 +342,71 @@ class TestMusic(BaseCase):
|
|||
|
||||
- 如果用例操作步骤是相同的,只是一些参数变化,尽量使用数据驱动来实现用例;
|
||||
|
||||
- 如果你需要使用外部文件 ==存放数据== 驱动的数据,==尽量不要因此引入依赖==,可以使用一些标准库能读取的文件格式,比如 `json、ini、CSV、xml、txt` 等文件格式;==不建议== 使用 `Yaml、Excel、MySQL` 等数据格式;
|
||||
- 如果你需要使用外部文件 ==存放数据驱动的数据,尽量不要因此引入依赖==,可以使用一些标准库能读取的文件格式,比如 `json、ini、CSV、xml、txt` 等文件格式;不建议使用 `Yaml、Excel、MySQL` 等数据格式;
|
||||
|
||||
- ==读取数据== 时也尽量使用标准库去做,如使用 `pandas` 处理 `CSV` 就属于大材小用了,正常的数据驱动还没到需要大数据分析来处理的地步;
|
||||
- ==读取数据时也尽量使用标准库去做==,如使用 `pandas` 处理 `CSV` 就属于大材小用了,正常的数据驱动还没到需要大数据分析来处理的地步;
|
||||
|
||||
- 数据驱动的外部文件存放在 ==widget/ddt/== 目录下;
|
||||
- 数据驱动的 ==外部文件存放在widget/ddt/== 目录下;
|
||||
|
||||
- 数据驱动的写法:
|
||||
- ==数据驱动的写法:==
|
||||
|
||||
```python
|
||||
@pytest.mark.parametrize("value", data)
|
||||
def test_smb_049(self, value):
|
||||
```
|
||||
|
||||
以上这种参数化的写法本身没什么问题,但是,这里必须要补充一个没有用的小知识:
|
||||
|
||||
- 如果参数化数据里面的字符会原封不动的输出到 `item.name` 里面,显示非常不优雅,而且可能会引入一些意想不到的问题,可以感受一下:
|
||||
|
||||
参数:
|
||||
|
||||
```python
|
||||
data = [
|
||||
"一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三",
|
||||
"qwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyui",
|
||||
"12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678",
|
||||
]
|
||||
```
|
||||
|
||||
终端日志打印出来,现象是这样色儿的:
|
||||
|
||||
```shell
|
||||
test_smb_049.py::TestFileManager::test_smb_049[一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三]
|
||||
test_smb_049.py::TestFileManager::test_smb_049[qwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyui]
|
||||
test_smb_049.py::TestFileManager::test_smb_049[12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678]
|
||||
```
|
||||
|
||||
说实话,看着心里堵得慌,如果这里面包含一些**特殊字符**或者是**超长**,可能还会有一些很奇妙的事情发生。
|
||||
|
||||
- parametrize 里面有个参数:==ids==,可以解决此类问题,就像这样:
|
||||
|
||||
```python
|
||||
@pytest.mark.parametrize("value", data, ids=[1, 2, 3])
|
||||
```python hl_lines="1"
|
||||
@pytest.mark.parametrize("value", data)
|
||||
def test_smb_049(self, value):
|
||||
...
|
||||
```
|
||||
|
||||
以上这种参数化的写法本身没什么问题;
|
||||
|
||||
但是,这里必须要补充一个没有用的小知识:
|
||||
|
||||
- ==使用 ids 参数;==
|
||||
|
||||
再来感受一下:
|
||||
==加 ids 参数之前:==
|
||||
|
||||
```shell
|
||||
test_smb_049.py::TestFileManager::test_smb_049[1]
|
||||
test_smb_049.py::TestFileManager::test_smb_049[2]
|
||||
test_smb_049.py::TestFileManager::test_smb_049[3]
|
||||
```
|
||||
如果参数化数据里面的字符会原封不动的输出到 `item.name` 里面,显示非常不优雅,而且可能会引入一些意想不到的问题,可以感受一下:
|
||||
|
||||
明显好多了,所以尽量使用 ids 这个参数。
|
||||
参数:
|
||||
|
||||
```python
|
||||
data = [
|
||||
"一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三",
|
||||
"qwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyui",
|
||||
"12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678",
|
||||
]
|
||||
```
|
||||
|
||||
- 不建议使用 `fixture` 的数据驱动方式,框架虽然支持,但可读性比较差;如果你不知道这句话在说啥,那你可以忽略,我也不打算详细说这种实现方式,操作比较骚。
|
||||
终端日志打印出来,现象是这样色儿的:
|
||||
|
||||
```shell
|
||||
test_smb_049.py::TestFileManager::test_smb_049[一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三]
|
||||
test_smb_049.py::TestFileManager::test_smb_049[qwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyui]
|
||||
test_smb_049.py::TestFileManager::test_smb_049[12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678]
|
||||
```
|
||||
|
||||
说实话,看着心里堵得慌,如果这里面包含一些**特殊字符**或者是**超长**,可能还会有一些很奇妙的事情发生。
|
||||
|
||||
==加 ids 参数之后:==
|
||||
|
||||
```python hl_lines="1"
|
||||
@pytest.mark.parametrize("value", data, ids=[1, 2, 3])
|
||||
def test_smb_049(self, value):
|
||||
...
|
||||
```
|
||||
|
||||
再来感受一下:
|
||||
|
||||
```shell
|
||||
test_smb_049.py::TestFileManager::test_smb_049[1]
|
||||
test_smb_049.py::TestFileManager::test_smb_049[2]
|
||||
test_smb_049.py::TestFileManager::test_smb_049[3]
|
||||
```
|
||||
|
||||
明显好多了,所以尽量使用 ids 这个参数。
|
||||
|
||||
- 不建议使用 `fixture` 的数据驱动方式,框架虽然支持,但可读性比较差;
|
||||
|
||||
如果你不知道这句话在说啥,那你可以忽略,我也不打算详细说这种实现方式,操作比较骚。
|
||||
|
||||
### 5.4. 断言资源
|
||||
|
||||
|
@ -346,11 +427,13 @@ class TestMusic(BaseCase):
|
|||
|
||||
- ==确保一个资源在一次用例执行中只需要下载一次==,如果每次使用的时候都去下载,这样可能会耗费大量的网络资源,而因为先判断本地是否存在此资源,如果不存在再去下载;
|
||||
|
||||
- 测试用例执行过程中,你可能需要将资源拷贝到对应的测试目录下,比如将 mp3 文件拷贝到 `~/Music` 目录下,但是我们更建议你使用发送快捷链接的方式替代拷贝的操作,因为在拷贝大文件时是很消耗系统资源的,而创建链接则不会;
|
||||
- 测试用例执行过程中,你可能需要将资源拷贝到对应的测试目录下;
|
||||
|
||||
```python
|
||||
class DeepinMusicWidget:
|
||||
|
||||
比如将 mp3 文件拷贝到 `~/Music` 目录下,但是我们更建议你使用发送快捷链接的方式替代拷贝的操作,因为在拷贝大文件时是很消耗系统资源的,而创建链接则不会;
|
||||
|
||||
```python
|
||||
class DeepinMusicWidget:
|
||||
|
||||
@classmethod
|
||||
def recovery_many_movies_in_movie_by_cmd(cls):
|
||||
"""恢复多个视频文件至视频目录中"""
|
||||
|
@ -366,13 +449,16 @@ class TestMusic(BaseCase):
|
|||
cls.run_cmd(
|
||||
f"cd {code_path}/;"
|
||||
f"{cls.wget_file('auto.zip') if flag else ''}"
|
||||
f"ln -s {code_path}/* {work_path}/ > /dev/null 2>&1"
|
||||
)
|
||||
```
|
||||
f"ln -s {code_path}/* {work_path}/ > /dev/null 2>&1"
|
||||
)
|
||||
```
|
||||
|
||||
资源下载过程中注意超时的问题,如果你的测试资源很大,要特别注意这问题,如果你使用强制等待下载结束( `os.system` ),可能会造成用例执行时长变得不可接受,目前我们发现在持续集成环境执行时网络下载速度很慢,所以超时机制是很有必要的;`run_cmd` 方法有一个默认超时的时间,你可以根据资源大小对超时时间进行调整;
|
||||
资源下载过程中注意 ==超时== 的问题;
|
||||
|
||||
如果你的测试资源很大,要特别注意这问题,如果你使用强制等待下载结束( `os.system` ),可能会造成用例执行时长变得不可接受;
|
||||
|
||||
在持续集成环境执行时网络下载速度很慢,所以超时机制是很有必要的;`run_cmd` 方法有一个默认超时的时间,你可以根据资源大小对超时时间进行调整;
|
||||
|
||||
|
||||
## 6. 标签化管理规范
|
||||
|
||||
|
@ -382,7 +468,7 @@ class TestMusic(BaseCase):
|
|||
|
||||
为了提醒标记,执行用例时在首行会输出 `ERROR` 日志: `CSV 文件里面没有对应的 ID`;
|
||||
|
||||
如果 `CSV` 文件里面没有对应 ID,后续在批量执行的时候,这些用例是不会执行的。
|
||||
==如果 CSV 文件里面没有对应 ID,后续在批量执行的时候,这些用例是不会执行的。==
|
||||
|
||||
### 6.2. 名称一致
|
||||
|
||||
|
@ -390,7 +476,7 @@ class TestMusic(BaseCase):
|
|||
|
||||
举例:
|
||||
|
||||
```python title="test_music_679537.py"
|
||||
```python title="test_music_679537.py" hl_lines="3"
|
||||
class TestMusic:
|
||||
|
||||
def test_music_679537():
|
||||
|
@ -401,157 +487,45 @@ class TestMusic:
|
|||
|
||||
框架底层代码实现是将 ==CSV 文件的名称== 与 ==用例脚本名称== 进行对应(建立映射);
|
||||
|
||||
|
||||
|
||||
## 二、分支及 tag 管理规范
|
||||
|
||||
参考《[自动化测试代码管理规范](https://filewh.uniontech.com/lib/d01a57df-cba6-44f2-af8e-4cc412ad1880/file/01.%E4%BA%A7%E5%93%81%E5%BC%80%E5%8F%91%E4%BD%93%E7%B3%BB/02%20%E4%BA%A7%E5%93%81%E7%A0%94%E5%8F%91/01-3%20%E6%B5%8B%E8%AF%95%E8%BF%87%E7%A8%8B/%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95/02-%E8%A7%84%E8%8C%83/%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E4%BB%A3%E7%A0%81%E7%AE%A1%E7%90%86%E8%A7%84%E8%8C%83%20V2.0.pdf)》
|
||||
|
||||
### 2. 应用库 tag
|
||||
## 7. 子应用Tag管理规范
|
||||
|
||||
- 应用库 tag 根据应用交付节点生成,每次打 tag 之前,相关测试人员需要进行用例调试;
|
||||
|
||||
- 调试用例是指的在全架构(x86、arm、mips)上调试通过;
|
||||
- 调试用例是指的在全架构上调试通过;
|
||||
|
||||
- 用例通过率达到 **90%** 以上才能打 tag,通过 Jenkins 执行器执行用例,保留通过率结果;
|
||||
- ==tag 号怎么打?==
|
||||
|
||||
- 用例通过率:通过用例数 / (总用例数 - 已废弃用例) *跳过的用例不算通过*
|
||||
- [Jenkins 执行器](https://jenkinswh.uniontech.com/view/CI/job/chengdu/job/AT_test/job/all_client_test/)
|
||||
根据持续集成的要求生成,其中应用版本号需要与项目经理确认本次即将集成的应用版本号是多少;
|
||||
|
||||
- 你可能会在一个交付周期内持续的进行AT用例调试,但是最终 AT 用例打 tag 的应用版本,**需要使用应用集成交付的最新应用版本**,可以使用应用的提测版本;一定要确保调试用例的应用版本是最新的,不然集成进去之后,持续集成就会出问题;
|
||||
tag 的 commit 信息格式:
|
||||
|
||||
- tag 号怎么打?
|
||||
```ini title="# commit msg"
|
||||
version:5.6.5
|
||||
```
|
||||
|
||||
其中 `5.6.5` 写应用的集成版本号。
|
||||
|
||||
根据持续集成的要求生成,其中应用版本号需要与项目经理确认本次即将集成的应用版本号是多少;
|
||||
|
||||
tag 的 commit 信息格式:
|
||||
|
||||
```ini
|
||||
# commit msg
|
||||
version:5.6.5
|
||||
```
|
||||
|
||||
其中 `5.6.5` 写应用的集成版本号。
|
||||
|
||||
生成 tag 的命令参考:[《Git 标签》](http://10.8.10.215/README.html#git )
|
||||
|
||||
### 3. 基础框架 tag
|
||||
|
||||
基础框架 tag 不与业务挂钩,根据自身的功能开发按需发布版本,在根目录下 `CURRENT` 文件中记录的当前版本号和历史版本号,及其对应新增了哪些功能,有助于应用选择合适的基础框架版本。
|
||||
|
||||
```ini
|
||||
# CURRENT
|
||||
[current]
|
||||
tag = 0.9.5
|
||||
```
|
||||
|
||||
应用库根目录下的 `control` 文件记录当前应用库依赖的基础库版本。
|
||||
|
||||
```ini
|
||||
# control
|
||||
[Depends]
|
||||
autotest-basic-frame = 0.9.5
|
||||
```
|
||||
|
||||
用例在执行时会校验两个文件的版本号是否一致,如果不一致,会打印 `error` 日志。
|
||||
|
||||
## 三、仓库权限管理
|
||||
|
||||
### 1. 基础框架
|
||||
|
||||
- 自动化测试基础框架仓库:https://github.com/linuxdeepin/deepin-autotest-framework
|
||||
|
||||
|
||||
### 2. 应用仓库
|
||||
|
||||
- 自动化应用仓库: `https://gerrit.uniontech.com/admin/repos/autotest_ + app_name`
|
||||
|
||||
链接后面的 `app_name` 中间以下划线连接,比如音乐:https://gerrit.uniontech.com/admin/repos/autotest_deepin_music
|
||||
|
||||
|
||||
## 四、方法编写&调用规范
|
||||
|
||||
方法编写整体设计思路参考:[《AT应用库设计方案》]
|
||||
|
||||
### 1. 方法编写
|
||||
|
||||
写方法的时候注意方法归属,比如文件管理器的界面区域划分为:`TitleWidget` 、`RightViewWidget`、`LeftViewWidget` 、`PopWidget`,方法是在哪个区域操作的,就写在哪个类里面。
|
||||
|
||||
举例:
|
||||
|
||||
```python
|
||||
from apps.dde_file_manager.widget import BaseWidget # dde_file_manager 为仓库名称
|
||||
|
||||
class TitleWidget(BaseWidget):
|
||||
"""标题栏方法类"""
|
||||
|
||||
def click_xxx_in_title_by_ui(self):
|
||||
"""点击标题栏xxx"""
|
||||
# self.dog.find_element_by_attr("xxxx").click()
|
||||
self.click(*self.ui.btn_center("xxx"))
|
||||
```
|
||||
|
||||
- 动作开头,注意是动词
|
||||
|
||||
```asciiarmor
|
||||
click
|
||||
double_click
|
||||
right_click
|
||||
get
|
||||
make
|
||||
```
|
||||
|
||||
- 元素对象名称
|
||||
|
||||
- 界面元素直接与元素名称相同,没有名称的就取一个好听易懂的名字。
|
||||
|
||||
- **加上类的关键词**
|
||||
|
||||
- 避免方法重名,同时可以标记区域。
|
||||
|
||||
- 标定操作方法
|
||||
|
||||
```asciiarmor
|
||||
by_ui
|
||||
by_attr
|
||||
by_mk
|
||||
by_img
|
||||
```
|
||||
|
||||
### 2. 方法调用
|
||||
|
||||
- 在用例中调用方法,通过该应用唯一的出口进行调用,比如文管:
|
||||
|
||||
```python
|
||||
class DfmWidget(TitleWidget, RightViewWidget, LeftViewWidget, PopWidget):
|
||||
pass
|
||||
```
|
||||
|
||||
**不要在用例中单独去调用** `TitleWidget` 、`RightViewWidget`、`LeftViewWidget` 、`PopWidget` 这些类,否则后期用例会变得不好维护;
|
||||
|
||||
## 其他规范
|
||||
## 8. 其他规范
|
||||
|
||||
- 不写 `if __name__ == '__main__':`,不写多余的代码;
|
||||
- 统一文件注释头。
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
# _*_ coding:utf-8 _*_
|
||||
"""
|
||||
:Author:email@uniontech.com
|
||||
:Date :${DATE} ${TIME}
|
||||
"""
|
||||
```
|
||||
- 日志打印要在方法最前面,否则代码报错没有日志输出,不好定位问题。(我们会考虑继续使用拦截器打印日志)
|
||||
|
||||
- 所有的操作都需要有日志,包括 `sleep()`,我们会重写一个有日志输入的 `sleep`。
|
||||
- 业务层日志级别为 `INFO`。
|
||||
- hook 函数只能写到根目录下的 `conftest.py` 里面。
|
||||
- `apps` 目录下的 `conftest.py` 原则上不会新增 `fixture`。
|
||||
- 固定目录或元素控件的操作,将操作方法写死,文件类操作将文件名留参数。
|
||||
```python title="xxx.py"
|
||||
#!/usr/bin/env python3
|
||||
# _*_ coding:utf-8 _*_
|
||||
"""
|
||||
:Author:email@uniontech.com
|
||||
:Date :${DATE} ${TIME}
|
||||
"""
|
||||
```
|
||||
|
||||
- 日志打印要在方法最前面,否则代码报错没有日志输出,不好定位问题;
|
||||
- hook 函数只能写到根目录下的 `conftest.py` 里面;
|
||||
- `apps` 目录下的 `conftest.py` 原则上不会写 `fixture`;
|
||||
- 固定目录或元素控件的操作,将操作方法写死,类似文件的操作可以将文件名留参数;
|
||||
- 路径拼接规范:
|
||||
- 系统中固定目录,路径拼接时使用波浪符号,比如:`~/Desktop/`,下层使用 `os.path.expanduser()`,它可以自动识别波浪符号。
|
||||
- 项目下路径使用配置文件中的路径,比如:`Config.BASE_PATH`,因为项目是可以在任意路径运行的,需要动态拼接路径。
|
||||
- 系统中固定目录,路径拼接时使用波浪符号,比如:`~/Desktop/`,下层使用 `os.path.expanduser()`,它可以自动识别波浪符号;
|
||||
- 项目下路径使用配置文件中的路径,比如:`Config.BASE_PATH`,因为项目是可以在任意路径运行的,需要动态拼接路径。
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
# AT 执行器使用指北
|
||||
|
||||
```plain
|
||||
# =============================================
|
||||
# Attribution : Chengdu Test Department
|
||||
# Time : 2022/5/25
|
||||
# Author : litao
|
||||
# =============================================
|
||||
```
|
||||
Jenkins url: [https://jenkinswh.uniontech.com/view/CI/job/chengdu/job/AT_test/](https://jenkinswh.uniontech.com/view/CI/job/chengdu/job/AT_test/)
|
||||
## 1、功能介绍
|
||||
|
||||
* 支持任意测试机系统语言设置,分辨率设置及用例执行环境搭建;
|
||||
* 支持 IP 为 15 网段的 AMD 架构测试机镜像装机;
|
||||
* 支持任意测试机指定应用,指定范围标签的用例执行;
|
||||
* 支持任意测试机状态检查,是否有正在运行的测试;
|
||||
* 支持配置用例执行时长,防止任务阻塞;
|
||||
* 支持根据应用版本自动查找对应的用例 tag;
|
||||
* 支持异常处理和测试完成的实时消息通知;
|
||||
## 2、Job 介绍
|
||||
|
||||
以下按执行流程的顺序介绍,每一步都可以单独执行。
|
||||
|
||||
### 1、主入口
|
||||
|
||||
Jenkins url: [https://jenkinswh.uniontech.com/view/CI/job/chengdu/job/AT_test/job/AT_test/](https://jenkinswh.uniontech.com/view/CI/job/chengdu/job/AT_test/job/AT_test/)
|
||||
|
||||
整个流程的主入口,通过这个入口,连同整个测试流程,镜像装机,环境部署,测试应用及生成报告。
|
||||
|
||||
参数介绍:
|
||||
|
||||
* 测试机:所有规整到固定区域的测试机,通过测试同学对测试机的习惯命名,在后台映射测试机的详细信息,括号中为测试机 IP 的最后一位;
|
||||
* 测试应用:指定的测试应用的包名,系统根据名称自动拉取对应的仓库代码;
|
||||
* deb包下载地址:测试上述应用时,需要安装的deb包下载地址,多个地址用“,”隔开,可以为空;
|
||||
* 范围标签:执行测试用例的标签范围,对应用例代码 csv 文件中的标签信息,以 pytest 的mark语法编写;
|
||||
* 系统语言:设置测试机执行用例时的系统语言环境;
|
||||
* 分辨率:设置测试机执行用例时的系统分辨率环境;
|
||||
* 镜像地址:镜像仓库的下载地址,通过 PXE 装机,可以为空,则直接跳过装机环节(目前仅支持部分 AMD 架构的装机);
|
||||
### 2、PXE 装机
|
||||
|
||||
Jenkins url: [https://jenkinswh.uniontech.com/view/CI/job/chengdu/job/AT_test/job/IOS_install/](https://jenkinswh.uniontech.com/view/CI/job/chengdu/job/AT_test/job/IOS_install/)
|
||||
|
||||
输入测试机的用户名,IP,密码,镜像地址后,自动装机,目前仅支持固定 15 网段的部分 AMD 架构的测试机。
|
||||
|
||||
### 3、次主入口
|
||||
|
||||
Jenkins url: [https://jenkinswh.uniontech.com/view/CI/job/chengdu/job/AT_test/job/all_client_test/](https://jenkinswh.uniontech.com/view/CI/job/chengdu/job/AT_test/job/all_client_test/)
|
||||
|
||||
该入口与主入口功能基本一致,只是剥离了PXE装机流程,支持任意测试机的执行流程。
|
||||
|
||||
### 4、环境部署
|
||||
|
||||
Jenkins url:[https://jenkinswh.uniontech.com/view/CI/job/chengdu/job/AT_test/job/env/build?delay=0sec](https://jenkinswh.uniontech.com/view/CI/job/chengdu/job/AT_test/job/env/build?delay=0sec)
|
||||
|
||||
设置测试机的系统语言,分辨率及安装测试所需的依赖包。
|
||||
|
||||
### 5、发送代码
|
||||
|
||||
Jenkins url: [https://jenkinswh.uniontech.com/view/CI/job/chengdu/job/AT_test/job/send_code/](https://jenkinswh.uniontech.com/view/CI/job/chengdu/job/AT_test/job/send_code/)
|
||||
|
||||
根据测试应用名称,拉取对应的应用库代码,并根据测试机上应用版本切换到对应的tag版本,若未找到tag版本,则使用最新的应用库代码,再根据应用库代码中配置的基础库版本,拉取基础库代码。
|
||||
|
||||
### 6、用例执行
|
||||
|
||||
Jenkins url: [https://jenkinswh.uniontech.com/view/CI/job/chengdu/job/AT_test/job/run_test/](https://jenkinswh.uniontech.com/view/CI/job/chengdu/job/AT_test/job/run_test/)
|
||||
|
||||
运行测试机上的用例
|
||||
|
||||
|
||||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
```shell
|
||||
# ================================================
|
||||
# Attribution : Chengdu Testing Department
|
||||
# Time : 2022/6/16
|
||||
# Author : mikigo
|
||||
# ================================================
|
||||
```
|
||||
|
|
|
@ -1 +1,7 @@
|
|||
---
|
||||
hide:
|
||||
- navigation
|
||||
- toc.integrate
|
||||
---
|
||||
|
||||
--8<-- "RELEASE.md"
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
template: no_busuanzi.html
|
||||
hide:
|
||||
- date
|
||||
- git-revision-date-localized
|
||||
- navigation
|
||||
- toc
|
||||
- git-authors
|
||||
comments: true
|
||||
---
|
||||
|
||||
|
||||
|
||||
# 留言
|
|
@ -1 +1,7 @@
|
|||
---
|
||||
hide:
|
||||
- navigation
|
||||
- toc.integrate
|
||||
---
|
||||
|
||||
--8<-- "README.md"
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
{{ super() }}
|
||||
{% endblock %}
|
|
@ -1,11 +1,11 @@
|
|||
{% if page.meta.comments %}
|
||||
<h2 id="__comments">{{ lang.t("meta.comments") }}</h2>
|
||||
<!--<h2 id="__comments">{{ lang.t("meta.comments") }}</h2>-->
|
||||
<!-- Insert generated snippet here -->
|
||||
<script src="https://giscus.app/client.js"
|
||||
data-repo="funny-dream/funny-docs"
|
||||
data-repo-id="R_kgDOJjlSqg"
|
||||
data-repo="linuxdeepin/deepin-autotest-framework"
|
||||
data-repo-id="R_kgDOKDOpHg"
|
||||
data-category="Announcements"
|
||||
data-category-id="DIC_kwDOJjlSqs4CWrT9"
|
||||
data-category-id="DIC_kwDOKDOpHs4CcRPx"
|
||||
data-mapping="pathname"
|
||||
data-strict="0"
|
||||
data-reactions-enabled="1"
|
||||
|
|
141
docs/常见问题.md
141
docs/常见问题.md
|
@ -1,79 +1,84 @@
|
|||
question【提交代码时提示邮箱或者名称不对】
|
||||
---
|
||||
hide:
|
||||
- navigation
|
||||
---
|
||||
|
||||
> 重新配置邮箱或者名称,然后重置生效:
|
||||
>
|
||||
> ```shell
|
||||
> git commit --amend --reset-author
|
||||
> ```
|
||||
## 提交代码时提示邮箱或者名称不对
|
||||
|
||||
question【怎么回滚到之前的版本】
|
||||
重新配置邮箱或者名称,然后重置生效:
|
||||
|
||||
> (1)查询历史提交记录
|
||||
>
|
||||
> ```shell
|
||||
> git log
|
||||
> ```
|
||||
>
|
||||
> 找到你要回滚的版本,复制 `hash` 值。
|
||||
>
|
||||
> - 注意:是 `commit` 空格之后的 `hash` 值,之前有同学复制的 `Change-Id:` 这样肯定报错。
|
||||
>
|
||||
> (2)回滚版本,不清除代码
|
||||
>
|
||||
> ```shell
|
||||
> git reset --soft ${hash}
|
||||
> ```
|
||||
>
|
||||
> (3)回滚版本,清除代码,慎用哈
|
||||
>
|
||||
> ```shell
|
||||
> git reset --hard ${hash}
|
||||
> ```
|
||||
```shell
|
||||
git commit --amend --reset-author
|
||||
```
|
||||
|
||||
question【解决 git status 中文显示的问题】
|
||||
## 怎么回滚到之前的版本
|
||||
|
||||
> ```shell
|
||||
> git config --global core.quotePath false
|
||||
> ```
|
||||
(1)查询历史提交记录
|
||||
|
||||
question【`apps` 目录下颜色有些是黄色的】
|
||||
```shell
|
||||
git log
|
||||
```
|
||||
|
||||
> 在 `Pycharm` 中 `apps` 目录下应用库文件是黄色的,编辑器识别不到代码新增和修改;
|
||||
>
|
||||
> 由于社区版 `Pycharm` 不能动态识别多仓库,需要在 setting 里面手动注册,操作步骤:
|
||||
>
|
||||
> `File` —> `Settings` —> `Version Control` —> 点 `+` 号 —> `Directory` 选中应用库工程目录 —> `VCS` 选中 `Git` —> `Apply`
|
||||
>
|
||||
> 如此就可以了。
|
||||
>
|
||||
> 专业版 `Pycharm` 不存在这个问题。
|
||||
>
|
||||
> question【执行 `env.sh` 报错 `$'\r':未找到命令`】
|
||||
>
|
||||
> 出现这个问题你应该是在 windows 上打开或编辑过 `env.sh` 脚本,windows下的换行是回车符+换行符,也就是`\r\n`,而 `Linxu` 下是换行符 `\n`,`Linux` 下不识别 `\r`,因此报错。
|
||||
>
|
||||
> 解决方案:
|
||||
>
|
||||
> ```shell
|
||||
> # 将 \r 替换为空
|
||||
> sudo sed -i 's/\r//' env.sh
|
||||
> ```
|
||||
找到你要回滚的版本,复制 `hash` 值。
|
||||
|
||||
question【怎样为单独某一条用例配置执行超时时间】
|
||||
- 注意:是 `commit` 空格之后的 `hash` 值,之前有同学复制的 `Change-Id:` 这样肯定报错。
|
||||
|
||||
> 在用例脚本中添加装饰器,如下:
|
||||
>
|
||||
> ```python
|
||||
> @pytest.mark.timeout(300) # 单位秒
|
||||
> def test_xxx_001():
|
||||
> pass
|
||||
> ```
|
||||
(2)回滚版本,不清除代码
|
||||
|
||||
question【如何修复子仓库 master 分支游离头(detached head)】
|
||||
```shell
|
||||
git reset --soft ${hash}
|
||||
```
|
||||
|
||||
> 修复所有子仓库默认master 分支游离头
|
||||
>
|
||||
> ```shell
|
||||
> cd youqu
|
||||
> git submodule foreach -q --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
|
||||
> ```
|
||||
(3)回滚版本,清除代码,慎用哈
|
||||
|
||||
```shell
|
||||
git reset --hard ${hash}
|
||||
```
|
||||
|
||||
## 解决 git status 中文显示的问题
|
||||
|
||||
```shell
|
||||
git config --global core.quotePath false
|
||||
```
|
||||
|
||||
## `apps` 目录下颜色有些是黄色的
|
||||
|
||||
在 `Pycharm` 中 `apps` 目录下应用库文件是黄色的,编辑器识别不到代码新增和修改;
|
||||
|
||||
由于社区版 `Pycharm` 不能动态识别多仓库,需要在 setting 里面手动注册,操作步骤:
|
||||
|
||||
`File` —`Settings` —`Version Control` —点 `+` 号 —`Directory` 选中应用库工程目录 —`VCS` 选中 `Git` —`Apply`
|
||||
|
||||
如此就可以了。
|
||||
|
||||
专业版 `Pycharm` 不存在这个问题。
|
||||
|
||||
执行 `env.sh` 报错 `$'\r':未找到命令`】
|
||||
|
||||
出现这个问题你应该是在 windows 上打开或编辑过 `env.sh` 脚本,windows下的换行是回车符+换行符,也就是`\r\n`,而 `Linxu` 下是换行符 `\n`,`Linux` 下不识别 `\r`,因此报错。
|
||||
|
||||
解决方案:
|
||||
|
||||
```shell
|
||||
# 将 \r 替换为空
|
||||
sudo sed -i 's/\r//' env.sh
|
||||
```
|
||||
|
||||
## 怎样为单独某一条用例配置执行超时时间
|
||||
|
||||
在用例脚本中添加装饰器,如下:
|
||||
|
||||
```python
|
||||
@pytest.mark.timeout(300) # 单位秒
|
||||
def test_xxx_001():
|
||||
pass
|
||||
```
|
||||
|
||||
## 如何修复子仓库 master 分支游离头(detached head)
|
||||
|
||||
修复所有子仓库默认master 分支游离头
|
||||
|
||||
```shell
|
||||
cd youqu
|
||||
git submodule foreach -q --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
|
||||
```
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
![](https://pic.imgdb.cn/item/64f054c2661c6c8e54ff477b.png)
|
||||
|
||||
# 智能化功能测试
|
||||
|
||||
![](https://pic.imgdb.cn/item/64f054c2661c6c8e54ff477b.png)
|
||||
|
||||
```python
|
||||
# Attribution :Chengdu Test Team
|
||||
# Date :2021/08/20
|
||||
```
|
||||
|
||||
此方案仍在演进中
|
||||
|
||||
仓库地址:https://gitlabcd.uniontech.com/autotest/cd-desktop-aitest
|
||||
仓库地址:[https://gitlabcd.uniontech.com/autotest/cd-desktop-aitest](ttps://gitlabcd.uniontech.com/autotest/cd-desktop-aitest)
|
||||
|
||||
## 一、方案概述
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
![](https://pic.imgdb.cn/item/64f054c7661c6c8e54ff4be0.png)
|
||||
|
||||
# 智能化性能测试
|
||||
|
||||
![](https://pic.imgdb.cn/item/64f054c7661c6c8e54ff4be0.png)
|
||||
|
||||
~~~shell
|
||||
# =============================================
|
||||
# Attribution : Application Test Department III
|
||||
# Attribution :Chengdu Test Team
|
||||
# Time : 2023/1/3
|
||||
# =============================================
|
||||
~~~
|
||||
|
@ -15,7 +15,7 @@
|
|||
|
||||
通过自动化手段对应用进行性能测试,提供方便的环境部署、运行配置、用例编写等,用于桌面应用的冷热启动、资源拷贝、页面跳转等性能场景测试。
|
||||
|
||||
仓库地址:https://gerrit.uniontech.com/admin/repos/autotest-perf-aitest
|
||||
仓库地址:[https://gerrit.uniontech.com/admin/repos/autotest-perf-aitest](https://gerrit.uniontech.com/admin/repos/autotest-perf-aitest)
|
||||
|
||||
## 二、代码结构
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ $ bash env.sh
|
|||
|
||||
</div>
|
||||
|
||||
!!! Warning 注意
|
||||
!!! Warning "注意"
|
||||
如果你的测试机密码不是 `1` ,那需要在全局配置文件 `globalconfig.ini` 里面将 `PASSWORD` 配置项修改为当前测试机的密码。
|
||||
|
||||
### 2. 定制依赖
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
hide:
|
||||
- navigation
|
||||
---
|
||||
# 框架生态
|
||||
|
||||
## 插件生态
|
||||
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
---
|
||||
|
||||
:fontawesome-brands-github:{ .lg .middle } __Funnlog__
|
||||
|
||||
一个简单易用、功能强大的日志工具,只需要加一个装饰器,就能自动日志输出类里面所有的方法的功能说明。
|
||||
|
||||
[:octicons-arrow-right-24: 详情](https://linuxdeepin.github.io/funnylog){target="_blank"}
|
||||
|
||||
---
|
||||
|
||||
:fontawesome-brands-github:{ .lg .middle } __letmego__
|
||||
|
||||
一个控制 Python 函数执行的技术方案,目前主要应用场景是在自动化测试程序遇到不得不中断的场景下,如重启场景,需要实现自动化用例步骤执行过程中重启机器,机器重新启动之后,能再次继续紧接着重启前的用例步骤执行的功能。
|
||||
|
||||
[:octicons-arrow-right-24: 详情](https://linuxdeepin.github.io/letmego){target="_blank"}
|
||||
|
||||
---
|
||||
|
||||
:fontawesome-brands-github:{ .lg .middle } __pdocr-rpc__
|
||||
|
||||
基于 PaddleOCR 封装的 RPC 服务,包含客户端和服务端,客户端提供了一个简单易用的函数 ocr,通过不同的参数控制返回不同的值。
|
||||
|
||||
[:octicons-arrow-right-24: 详情](https://linuxdeepin.github.io/pdocr-rpc/){target="_blank"}
|
||||
|
||||
---
|
||||
|
||||
:fontawesome-brands-github:{ .lg .middle } __image-center__
|
||||
|
||||
图像识别定位某个元素在当前屏幕中的坐标,在自动化测试中获取到元素坐标之后,可以传入到键鼠工具,从而实现对目标元素的操作。
|
||||
|
||||
[:octicons-arrow-right-24: 详情](https://linuxdeepin.github.io/image-center/){target="_blank"}
|
||||
|
||||
</div>
|
||||
|
||||
## 衍生工具
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
---
|
||||
|
||||
:file_folder:{ .lg .middle } __工具库__
|
||||
|
||||
各种工具(Bug定级工具、备注模板、常用网址、内网激活等等)
|
||||
|
||||
[:octicons-arrow-right-24: 详情](http://youqu.uniontech.com/tool/){target="_blank"}
|
||||
|
||||
---
|
||||
|
||||
:file_folder:{ .lg .middle } __知识库__
|
||||
|
||||
知识库网站。
|
||||
|
||||
[:octicons-arrow-right-24: 详情](http://youqu.uniontech.com/docs/){target="_blank"}
|
||||
|
||||
</div>
|
|
@ -1,7 +1,14 @@
|
|||
# 自动化测试架构设计规划
|
||||
|
||||
- 分类:/
|
||||
- 架构师:/
|
||||
```shell
|
||||
# ====================================
|
||||
# Author : mikigo
|
||||
# ====================================
|
||||
```
|
||||
|
||||
[comment]: <> (- 分类:/)
|
||||
|
||||
[comment]: <> (- 架构师:/)
|
||||
- 目标:
|
||||
- 应用 AT 架构工程化,参考性能自动化工程完成工程化改造。
|
||||
- 应用间用例解耦,解除所有交叉调用的方法,各应用能跟随自身迭代周期独立维护 AT 用例。
|
||||
|
@ -192,7 +199,7 @@
|
|||
|
||||
1.3、操作层文件名均以 `widget` 结尾,类名以 `Widget` 结尾,如:文件名 `music_widget.py` :
|
||||
|
||||
```python
|
||||
```python title="music_widget.py"
|
||||
class MusicWidget:
|
||||
"""音乐的操作方法类"""
|
||||
|
||||
|
@ -210,7 +217,7 @@ class MusicWidget:
|
|||
|
||||
比如:几乎所有多媒体应用都需要通过文管加载资源,调起的文管对话框实际为 `dde-desktop`,因此将 `dde_desktop_public_widget.py` 放到 `public` 里面:
|
||||
|
||||
```python
|
||||
```python title="dde_desktop_public_widget.py"
|
||||
class DdeDesktopPublicWidget:
|
||||
"""公共-桌面的操作方法"""
|
||||
|
||||
|
|
34
mkdocs.yml
34
mkdocs.yml
|
@ -14,8 +14,8 @@ theme:
|
|||
name: Switch to light mode
|
||||
- media: '(prefers-color-scheme: dark)'
|
||||
scheme: slate
|
||||
primary: custom
|
||||
accent: amber
|
||||
primary: black
|
||||
accent:
|
||||
toggle:
|
||||
icon: material/lightbulb-outline
|
||||
name: Switch to dark mode
|
||||
|
@ -33,6 +33,7 @@ theme:
|
|||
- navigation.sections
|
||||
- navigation.top
|
||||
- navigation.tracking
|
||||
- navigation.tabs
|
||||
- search.highlight
|
||||
- search.share
|
||||
- search.suggest
|
||||
|
@ -85,6 +86,8 @@ markdown_extensions:
|
|||
plugins:
|
||||
- git-revision-date-localized:
|
||||
locale: zh
|
||||
exclude:
|
||||
- comments.md
|
||||
- git-authors:
|
||||
- search
|
||||
- mike
|
||||
|
@ -118,7 +121,7 @@ extra_css:
|
|||
nav:
|
||||
- 快速开始: index.md
|
||||
|
||||
- 详细功能介绍:
|
||||
- 详细功能:
|
||||
- 框架功能介绍/环境部署.md
|
||||
- 框架功能介绍/全局配置.md
|
||||
- 框架功能介绍/执行管理器.md
|
||||
|
@ -139,32 +142,27 @@ nav:
|
|||
- 框架功能介绍/Wayland适配.md
|
||||
- 框架功能介绍/静态代码扫描.md
|
||||
|
||||
- 版本更新:
|
||||
- RELEASE.md
|
||||
|
||||
- 框架设计:
|
||||
- 自动化测试架构设计v1.0.md
|
||||
- AT基础框架设计方案.md
|
||||
- AT应用库设计方案.md
|
||||
|
||||
- 操作规范&指引:
|
||||
- 规范建议:
|
||||
- AT开发规范.md
|
||||
- AT经验总结.md
|
||||
- AT用例筛选指北.md
|
||||
- AT执行器使用指北.md
|
||||
|
||||
- 框架生态:
|
||||
- letmego: https://linuxdeepin.github.io/letmego" target="_blank
|
||||
- funnylog: https://linuxdeepin.github.io/funnylog" target="_blank
|
||||
- pdocr-rpc: https://linuxdeepin.github.io/pdocr-rpc" target="_blank
|
||||
- image-center: https://linuxdeepin.github.io/image-center" target="_blank
|
||||
|
||||
- 其他:
|
||||
- 技术演进:
|
||||
- 智能化功能测试.md
|
||||
- 智能化性能测试.md
|
||||
|
||||
- 框架生态:
|
||||
- 框架生态.md
|
||||
|
||||
- 版本更新:
|
||||
- RELEASE.md
|
||||
|
||||
- 常见问题: 常见问题.md
|
||||
|
||||
- 工具库: http://youqu.uniontech.com/tool" target="_blank
|
||||
|
||||
- 知识库: http://youqu.uniontech.com/docs" target="_blank
|
||||
- 留言:
|
||||
- comments.md
|
Loading…
Reference in New Issue