├── Base
├── __init__.py
├── __pycache__
│ ├── BaseFile.cpython-34.pyc
│ ├── BaseInit.cpython-34.pyc
│ ├── BaseLog.cpython-34.pyc
│ ├── BaseYaml.cpython-34.pyc
│ ├── __init__.cpython-34.pyc
│ ├── BaseError.cpython-34.pyc
│ ├── BaseExcel.cpython-34.pyc
│ ├── BasePickle.cpython-34.pyc
│ ├── BaseRunner.cpython-34.pyc
│ ├── BaseOperate.cpython-34.pyc
│ ├── BaseElementEnmu.cpython-34.pyc
│ └── BaseStatistics.cpython-34.pyc
├── BaseFile.py
├── BaseInit.py
├── BaseError.py
├── BasePickle.py
├── BaseElementEnmu.py
├── BaseRunner.py
├── BaseYaml.py
├── BaseEmail.py
├── BaseStatistics.py
├── BaseLog.py
├── BaseExcel.py
└── BaseOperate.py
├── Runner
├── __init__.py
└── runner.py
├── PageObject
├── __init__.py
├── Home
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── LoginPage.cpython-34.pyc
│ │ ├── __init__.cpython-34.pyc
│ │ └── LoginFailPage.cpython-34.pyc
│ ├── LoginPage.py
│ └── LoginFailPage.py
├── __pycache__
│ ├── Pages.cpython-34.pyc
│ ├── SumResult.cpython-34.pyc
│ └── __init__.cpython-34.pyc
├── My
│ ├── __pycache__
│ │ └── HotTopicPage.cpython-34.pyc
│ └── HotTopicPage.py
├── cnblogs
│ ├── __pycache__
│ │ └── AspNetPage.cpython-34.pyc
│ └── AspNetPage.py
├── SumResult.py
└── Pages.py
├── TestCase
├── __init__.py
├── CnblogsTest.py
├── MyTest.py
└── HomeTest.py
├── use.md
├── CHANGELOG.md
├── Img
├── sum.png
└── detail.jpg
├── Yamls
├── config.yaml
├── home
│ ├── LoginFail.yaml
│ └── Login.yaml
├── my
│ └── HotTopic.yaml
└── cnblogs
│ └── AspNet.yaml
├── log
├── info.pickle
└── sum.pickle
├── start_test.bat
├── Report
└── Report.xlsx
├── exe
└── chromedriver.exe
├── .idea
├── vcs.xml
├── misc.xml
├── modules.xml
├── wise-oper.iml
└── workspace.xml
└── README.md
/Base/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Runner/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/PageObject/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/TestCase/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/PageObject/Home/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/use.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/use.md
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/CHANGELOG.md
--------------------------------------------------------------------------------
/Img/sum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/Img/sum.png
--------------------------------------------------------------------------------
/Img/detail.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/Img/detail.jpg
--------------------------------------------------------------------------------
/Yamls/config.yaml:
--------------------------------------------------------------------------------
1 | #url: https://www.cnblogs.com
2 | url: https://testerhome.com/
--------------------------------------------------------------------------------
/log/info.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/log/info.pickle
--------------------------------------------------------------------------------
/start_test.bat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/start_test.bat
--------------------------------------------------------------------------------
/Report/Report.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/Report/Report.xlsx
--------------------------------------------------------------------------------
/exe/chromedriver.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/exe/chromedriver.exe
--------------------------------------------------------------------------------
/Base/__pycache__/BaseFile.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/Base/__pycache__/BaseFile.cpython-34.pyc
--------------------------------------------------------------------------------
/Base/__pycache__/BaseInit.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/Base/__pycache__/BaseInit.cpython-34.pyc
--------------------------------------------------------------------------------
/Base/__pycache__/BaseLog.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/Base/__pycache__/BaseLog.cpython-34.pyc
--------------------------------------------------------------------------------
/Base/__pycache__/BaseYaml.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/Base/__pycache__/BaseYaml.cpython-34.pyc
--------------------------------------------------------------------------------
/Base/__pycache__/__init__.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/Base/__pycache__/__init__.cpython-34.pyc
--------------------------------------------------------------------------------
/Base/__pycache__/BaseError.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/Base/__pycache__/BaseError.cpython-34.pyc
--------------------------------------------------------------------------------
/Base/__pycache__/BaseExcel.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/Base/__pycache__/BaseExcel.cpython-34.pyc
--------------------------------------------------------------------------------
/Base/__pycache__/BasePickle.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/Base/__pycache__/BasePickle.cpython-34.pyc
--------------------------------------------------------------------------------
/Base/__pycache__/BaseRunner.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/Base/__pycache__/BaseRunner.cpython-34.pyc
--------------------------------------------------------------------------------
/Base/__pycache__/BaseOperate.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/Base/__pycache__/BaseOperate.cpython-34.pyc
--------------------------------------------------------------------------------
/PageObject/__pycache__/Pages.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/PageObject/__pycache__/Pages.cpython-34.pyc
--------------------------------------------------------------------------------
/Base/__pycache__/BaseElementEnmu.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/Base/__pycache__/BaseElementEnmu.cpython-34.pyc
--------------------------------------------------------------------------------
/Base/__pycache__/BaseStatistics.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/Base/__pycache__/BaseStatistics.cpython-34.pyc
--------------------------------------------------------------------------------
/PageObject/__pycache__/SumResult.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/PageObject/__pycache__/SumResult.cpython-34.pyc
--------------------------------------------------------------------------------
/PageObject/__pycache__/__init__.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/PageObject/__pycache__/__init__.cpython-34.pyc
--------------------------------------------------------------------------------
/PageObject/Home/__pycache__/LoginPage.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/PageObject/Home/__pycache__/LoginPage.cpython-34.pyc
--------------------------------------------------------------------------------
/PageObject/Home/__pycache__/__init__.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/PageObject/Home/__pycache__/__init__.cpython-34.pyc
--------------------------------------------------------------------------------
/PageObject/My/__pycache__/HotTopicPage.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/PageObject/My/__pycache__/HotTopicPage.cpython-34.pyc
--------------------------------------------------------------------------------
/PageObject/Home/__pycache__/LoginFailPage.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/PageObject/Home/__pycache__/LoginFailPage.cpython-34.pyc
--------------------------------------------------------------------------------
/PageObject/cnblogs/__pycache__/AspNetPage.cpython-34.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Louis-me/selenium/HEAD/PageObject/cnblogs/__pycache__/AspNetPage.cpython-34.pyc
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/log/sum.pickle:
--------------------------------------------------------------------------------
1 | (dp0
2 | Vfail
3 | p1
4 | L0L
5 | sVversion
6 | p2
7 | V2018.4.28
8 | p3
9 | sVsum
10 | p4
11 | L3L
12 | sVtestDate
13 | p5
14 | V2018-04-30 12:46:43
15 | p6
16 | sVpass
17 | p7
18 | L3L
19 | sVtestSumDate
20 | p8
21 | V75\u79d2
22 | p9
23 | s.
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/PageObject/SumResult.py:
--------------------------------------------------------------------------------
1 | from Base.BaseStatistics import countInfo, countSum
2 |
3 |
4 | def statistics_result(**kwargs):
5 | countInfo(result=kwargs["result"], testInfo=kwargs["testInfo"], caseName=kwargs["caseName"], name="chrome",
6 | driver=kwargs["driver"], logTest=kwargs["logTest"], testCase=kwargs["testCase"],
7 | testCheck=kwargs["testCheck"])
8 | countSum(kwargs["result"])
9 |
10 |
--------------------------------------------------------------------------------
/.idea/wise-oper.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/PageObject/Home/LoginPage.py:
--------------------------------------------------------------------------------
1 | from PageObject import Pages
2 | from Base.BaseYaml import getYam
3 |
4 |
5 | class LoginPage:
6 | def __init__(self, kwargs):
7 | _init = {"driver": kwargs["driver"], "test_msg": getYam(kwargs["path"]),
8 | "logTest": kwargs["logTest"], "caseName": kwargs["caseName"]}
9 | self.page = Pages.PagesObjects(_init)
10 |
11 | def operate(self): # 操作步骤
12 | self.page.operate()
13 |
14 | def checkPoint(self): # 检查点
15 | self.page.checkPoint()
16 |
17 |
18 | if __name__ == "__main__":
19 | pass
20 |
--------------------------------------------------------------------------------
/PageObject/Home/LoginFailPage.py:
--------------------------------------------------------------------------------
1 | from PageObject import Pages
2 | from Base.BaseYaml import getYam
3 |
4 |
5 | class LoginFailPage:
6 | def __init__(self, kwargs):
7 | _init = {"driver": kwargs["driver"], "test_msg": getYam(kwargs["path"]),
8 | "logTest": kwargs["logTest"], "caseName": kwargs["caseName"]}
9 | self.page = Pages.PagesObjects(_init)
10 |
11 | def operate(self): # 操作步骤
12 | self.page.operate()
13 |
14 | def checkPoint(self): # 检查点
15 | self.page.checkPoint()
16 |
17 |
18 | if __name__ == "__main__":
19 | pass
20 |
--------------------------------------------------------------------------------
/PageObject/My/HotTopicPage.py:
--------------------------------------------------------------------------------
1 | from PageObject import Pages
2 | from Base.BaseYaml import getYam
3 |
4 | '''
5 | 热门话题
6 | '''
7 |
8 |
9 | class HotTopicPage:
10 | def __init__(self, kwargs):
11 | _init = {"driver": kwargs["driver"], "test_msg": getYam(kwargs["path"]),
12 | "logTest": kwargs["logTest"], "caseName": kwargs["caseName"]}
13 | self.page = Pages.PagesObjects(_init)
14 |
15 | def operate(self): # 操作步骤
16 | self.page.operate()
17 |
18 | def checkPoint(self): # 检查点
19 | self.page.checkPoint()
20 |
21 |
22 | if __name__ == "__main__":
23 | pass
24 |
--------------------------------------------------------------------------------
/PageObject/cnblogs/AspNetPage.py:
--------------------------------------------------------------------------------
1 | from PageObject import Pages
2 | from Base.BaseYaml import getYam
3 |
4 | '''
5 | 博客园下的asp.net新手区
6 | '''
7 |
8 |
9 | class AspNetPage:
10 | def __init__(self, kwargs):
11 | _init = {"driver": kwargs["driver"], "test_msg": getYam(kwargs["path"]),
12 | "logTest": kwargs["logTest"], "caseName": kwargs["caseName"]}
13 | self.page = Pages.PagesObjects(_init)
14 |
15 | def operate(self): # 操作步骤
16 | self.page.operate()
17 |
18 | def checkPoint(self): # 检查点
19 | self.page.checkPoint()
20 |
21 |
22 | if __name__ == "__main__":
23 | pass
24 |
--------------------------------------------------------------------------------
/Base/BaseFile.py:
--------------------------------------------------------------------------------
1 | __author__ = 'shikun'
2 |
3 | import os
4 |
5 |
6 | '''
7 | 操作文件
8 | '''
9 |
10 |
11 | def write_data(f, method='w+', data=""):
12 | if not os.path.isfile(f):
13 | print('文件不存在,写入数据失败')
14 | else:
15 | with open(f, method, encoding="utf-8") as fs:
16 | fs.write(data + "\n")
17 |
18 |
19 | def mkdir_file(f, method='w+'):
20 | if not os.path.isfile(f):
21 | with open(f, method, encoding="utf-8") as fs:
22 | print("创建文件%s成功" % f)
23 | pass
24 | else:
25 | print("%s文件已经存在,创建失败" % f)
26 | pass
27 |
28 |
29 | def remove_file(f):
30 | if os.path.isfile(f):
31 | os.remove(f)
32 | else:
33 | print("%s文件不存在,无法删除" % f)
34 |
--------------------------------------------------------------------------------
/Yamls/home/LoginFail.yaml:
--------------------------------------------------------------------------------
1 | testinfo:
2 | - id: test001
3 | title: 登录失败
4 | launch: 1
5 | info: 打开testerhome
6 | testcase:
7 | - element_info: div.container>ul>li:nth-child(2)
8 | find_type: css
9 | operate_type: click
10 | info: 点击登录
11 | - element_info: input-lg
12 | find_type: class_name
13 | operate_type: send_keys
14 | msg: lose1
15 | info: 输入用户名lose1
16 | - element_info: user_password
17 | find_type: id
18 | operate_type: send_keys
19 | msg: 1231231232
20 | info: 输入密码1231231232
21 | - element_info: div.form-actions
22 | find_type: css
23 | operate_type: click
24 | info: 点击登录
25 |
26 | check:
27 | - element_info: div.alert-warning
28 | find_type: css
29 | info: 出现错误的密码登录不成功提示框
--------------------------------------------------------------------------------
/TestCase/CnblogsTest.py:
--------------------------------------------------------------------------------
1 | from Base.BaseRunner import ParametrizedTestCase
2 | import os
3 | import sys
4 | from PageObject.cnblogs.AspNetPage import AspNetPage
5 |
6 | PATH = lambda p: os.path.abspath(
7 | os.path.join(os.path.dirname(__file__), p)
8 | )
9 |
10 |
11 | class CnblogsTest(ParametrizedTestCase):
12 | def testAspNet(self):
13 | app = {"logTest": self.logTest, "driver": self.driver, "path": PATH("../Yamls/cnblogs/AspNet.yaml"),
14 | "caseName": sys._getframe().f_code.co_name}
15 |
16 | page = AspNetPage(app)
17 | page.operate()
18 | page.checkPoint()
19 |
20 | @classmethod
21 | def setUpClass(cls):
22 | super(CnblogsTest, cls).setUpClass()
23 |
24 | @classmethod
25 | def tearDownClass(cls):
26 | super(CnblogsTest, cls).tearDownClass()
27 |
--------------------------------------------------------------------------------
/Yamls/my/HotTopic.yaml:
--------------------------------------------------------------------------------
1 | testinfo:
2 | - id: test003
3 | title: 热门话题
4 | info: 打开testerhome
5 | testcase:
6 | - element_info: dropdown-avatar
7 | find_type: class_name
8 | operate_type: click
9 | info: 点击图像
10 | - element_info: //ul[@class='dropdown-menu']/li/a
11 | find_type: xpath
12 | operate_type: click
13 | info: 点击用户名
14 | - element_info: //ul[@class="list-group"]/li[1]/div/a[2]
15 | find_type: xpath
16 | operate_type: get_text
17 | info: 获取热门话题下的第一条标题
18 | - element_info: ul.list-group > li:nth-child(1) > div.title > a:nth-child(2)
19 | find_type: css
20 | operate_type: click
21 | info: 点击热门话题下的第一条标题
22 |
23 | check:
24 | - element_info: /html/head/title
25 | find_type: xpath
26 | operate_type: get_text
27 | check: compare
28 | info: 详情页的标题和历史标题相等
--------------------------------------------------------------------------------
/Yamls/cnblogs/AspNet.yaml:
--------------------------------------------------------------------------------
1 | testinfo:
2 | - id: test005
3 | title: .net分类下的详情页
4 | info: 打开博客园
5 | testcase:
6 | - element_info: cate_item_108698
7 | find_type: id
8 | operate_type: move_to_element
9 | info: 鼠标悬停到.net分类上
10 | - element_info: div.cate_content_block > ul > li:nth-child(1)
11 | find_type: css
12 | operate_type: click
13 | info: 点击新手区
14 | - element_info: div#post_list > div:nth-child(1) > div.post_item_body > h3 > a
15 | find_type: css
16 | operate_type: get_text
17 | info: 获取新手区推荐的第一条数据
18 | - element_info: div#post_list > div:nth-child(1) > div.post_item_body > h3 > a
19 | find_type: css
20 | operate_type: click
21 | info: 点击新手区推荐的第一条数据
22 |
23 | check:
24 | - element_info: /html/head/title
25 | find_type: xpath
26 | operate_type: get_text
27 | check: compare
28 | info: 详情页的标题和历史标题相等
--------------------------------------------------------------------------------
/Yamls/home/Login.yaml:
--------------------------------------------------------------------------------
1 | testinfo:
2 | - id: test001
3 | title: 登录成功
4 | info: 打开testerhome
5 | testcase:
6 | - element_info: div.container>ul>li:nth-child(2)
7 | find_type: css
8 | operate_type: click
9 | info: 点击登录
10 | - element_info: input-lg
11 | find_type: class_name
12 | operate_type: send_keys
13 | msg: lose
14 | info: 输入用户名lose
15 | - element_info: user_password
16 | find_type: id
17 | operate_type: send_keys
18 | msg: XXXXX
19 | info: 输入密码XXXXXX
20 | - element_info: div.form-actions
21 | find_type: css
22 | operate_type: click
23 | info: 点击登录
24 | - element_info: dropdown-avatar
25 | find_type: class_name
26 | operate_type: click
27 | info: 点击图像
28 |
29 | check:
30 | - element_info: //ul[@class='dropdown-menu']/li/a[contains(text(),'lose')]
31 | find_type: xpath
32 | info: 查找用户名lose成功
--------------------------------------------------------------------------------
/Base/BaseInit.py:
--------------------------------------------------------------------------------
1 | from Base.BaseElementEnmu import Element
2 | from Base.BasePickle import *
3 | from Base.BaseFile import *
4 |
5 | PATH = lambda p: os.path.abspath(
6 | os.path.join(os.path.dirname(__file__), p)
7 | )
8 |
9 |
10 | def mk_file():
11 | destroy()
12 | mkdir_file(PATH("../Log/"+Element.INFO_FILE))
13 | mkdir_file(PATH("../Log/"+Element.SUM_FILE))
14 |
15 | data = read(PATH("../Log/"+Element.INFO_FILE))
16 |
17 | data["version"] = "2018.4.28"
18 | data["sum"] = 0
19 | data["pass"] = 0
20 | data["fail"] = 0
21 | write(data=data, path=PATH("../Log/"+Element.SUM_FILE))
22 |
23 |
24 |
25 |
26 |
27 | def destroy():
28 | remove_file(PATH("../Log/"+Element.INFO_FILE))
29 | remove_file(PATH("../Log/"+Element.SUM_FILE))
30 | # remove_file(PATH("../Log/"+Element.DEVICES_FILE))
31 |
32 |
33 | if __name__ == '__main__':
34 | print(destroy())
35 | # print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
36 |
--------------------------------------------------------------------------------
/Runner/runner.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | __author__ = 'shikun'
4 | import sys
5 | sys.path.append("..")
6 | from Base.BaseRunner import ParametrizedTestCase
7 | from TestCase.HomeTest import HomeTest
8 | import unittest
9 | from Base.BaseInit import mk_file
10 | from Base.BaseStatistics import countDate, writeExcel
11 | from datetime import datetime
12 | from TestCase.MyTest import MyTest
13 | from TestCase.CnblogsTest import CnblogsTest
14 |
15 | def runnerCaseApp():
16 | start_time = datetime.now()
17 | suite = unittest.TestSuite()
18 | suite.addTest(ParametrizedTestCase.parametrize(HomeTest))
19 | suite.addTest(ParametrizedTestCase.parametrize(MyTest))
20 | # suite.addTest(ParametrizedTestCase.parametrize(CnblogsTest))
21 | unittest.TextTestRunner(verbosity=2).run(suite)
22 | end_time = datetime.now()
23 | countDate(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), str((end_time - start_time).seconds) + "秒")
24 |
25 |
26 | if __name__ == '__main__':
27 | mk_file()
28 | runnerCaseApp()
29 | writeExcel()
30 |
--------------------------------------------------------------------------------
/TestCase/MyTest.py:
--------------------------------------------------------------------------------
1 | from Base.BaseRunner import ParametrizedTestCase
2 | import os
3 | import sys
4 | from PageObject.My.HotTopicPage import HotTopicPage
5 | from PageObject.Home.LoginPage import LoginPage
6 | PATH = lambda p: os.path.abspath(
7 | os.path.join(os.path.dirname(__file__), p)
8 | )
9 |
10 |
11 | class MyTest(ParametrizedTestCase):
12 | def login(self):
13 | app = {"logTest": self.logTest, "driver": self.driver, "path": PATH("../Yamls/home/Login.yaml"),
14 | "caseName": sys._getframe().f_code.co_name}
15 | page = LoginPage(app)
16 | page.operate()
17 |
18 | def testHotTopic(self):
19 | self.login()
20 | app = {"logTest": self.logTest, "driver": self.driver, "path": PATH("../Yamls/my/HotTopic.yaml"),
21 | "caseName": sys._getframe().f_code.co_name}
22 |
23 | page = HotTopicPage(app)
24 | page.operate()
25 | page.checkPoint()
26 |
27 | @classmethod
28 | def setUpClass(cls):
29 | super(MyTest, cls).setUpClass()
30 |
31 | @classmethod
32 | def tearDownClass(cls):
33 | super(MyTest, cls).tearDownClass()
34 |
--------------------------------------------------------------------------------
/Base/BaseError.py:
--------------------------------------------------------------------------------
1 | from Base.BaseElementEnmu import Element
2 |
3 | """
4 | element_info: 元素
5 | info: 用例说明
6 | current: 当前值
7 | history: 历史值
8 | type: 错误类型
9 | """
10 |
11 |
12 | def get_error(kw):
13 | elements = {
14 | Element.TIME_OUT: lambda: "==%s请求超时==" % kw["element_info"],
15 | Element.NO_SUCH: lambda: "==%s不存在==" % kw["element_info"],
16 | Element.WEB_DROVER_EXCEPTION: lambda: "==%s的driver错误==" % kw["element_info"],
17 | Element.INDEX_ERROR: lambda: "==%s索引错误==" % kw["element_info"],
18 | Element.STALE_ELEMENT_REFERENCE_EXCEPTION: lambda: "==%s页面元素已经发生==" % kw["element_info"],
19 | Element.DEFAULT_ERROR: lambda: "==请检查%s==" % kw["element_info"],
20 | Element.CONTRARY: lambda: "==检查点_%s失败_%s依然在页面==" % (kw["info"], kw["element_info"]),
21 | Element.CONTRARY_GETVAL: lambda: "==检查点_对比数据失败,当前取到到数据为:%s,历史取到数据为:%s" % (kw["current"], kw["history"]),
22 | Element.DEFAULT_CHECK: lambda: "==检查点_%s失败,请检查_%s==" % (kw["info"], kw["element_info"]),
23 | Element.COMPARE: lambda: "==检查点_对比数据失败,当前取到到数据为:%s,历史取到数据为:%s" % (kw["current"], kw["history"])
24 | }
25 | return elements[kw["type"]]()
26 |
--------------------------------------------------------------------------------
/TestCase/HomeTest.py:
--------------------------------------------------------------------------------
1 | from Base.BaseRunner import ParametrizedTestCase
2 | import os
3 | import sys
4 | from PageObject.Home.LoginPage import LoginPage
5 | from PageObject.Home.LoginFailPage import LoginFailPage
6 |
7 | PATH = lambda p: os.path.abspath(
8 | os.path.join(os.path.dirname(__file__), p)
9 | )
10 |
11 |
12 | class HomeTest(ParametrizedTestCase):
13 | def testALoginFail(self):
14 | app = {"logTest": self.logTest, "driver": self.driver, "path": PATH("../Yamls/home/LoginFail.yaml"),
15 | "caseName": sys._getframe().f_code.co_name}
16 |
17 | page = LoginFailPage(app)
18 | page.operate()
19 | page.checkPoint()
20 |
21 | def testBLogin(self):
22 | app = {"logTest": self.logTest, "driver": self.driver, "path": PATH("../Yamls/home/Login.yaml"),
23 | "caseName": sys._getframe().f_code.co_name}
24 |
25 | page = LoginPage(app)
26 | page.operate()
27 | page.checkPoint()
28 |
29 | @classmethod
30 | def setUpClass(cls):
31 | super(HomeTest, cls).setUpClass()
32 |
33 | @classmethod
34 | def tearDownClass(cls):
35 | super(HomeTest, cls).tearDownClass()
36 |
--------------------------------------------------------------------------------
/Base/BasePickle.py:
--------------------------------------------------------------------------------
1 | __author__ = "shikun"
2 | import pickle
3 | import os
4 |
5 | def write(data, path="data.pickle"):
6 | with open(path, 'wb') as f:
7 | pickle.dump(data, f, 0)
8 | def read(path):
9 | data = {}
10 | with open(path, 'rb') as f:
11 | try:
12 | data = pickle.load(f)
13 | except EOFError:
14 | data = {}
15 | # print("读取文件错误")
16 | return data
17 |
18 | def readInfo(path):
19 | data = []
20 | with open(path, 'rb') as f:
21 | try:
22 | data = pickle.load(f)
23 | print(data)
24 | except EOFError:
25 | data = []
26 | # print("读取文件错误")
27 | return data
28 |
29 |
30 |
31 | def writeInfo(data="", path="data.pickle"):
32 | """
33 |
34 | :type data: dict
35 | """
36 | _read = readInfo(path)
37 | result = []
38 | if _read:
39 | _read.append(data)
40 | result = _read
41 | else:
42 | result.append(data)
43 | with open(path, 'wb') as f:
44 | # print("------writeInfo-------")
45 | # print(result)
46 | pickle.dump(result, f)
47 |
48 | if __name__ == "__main__":
49 | # write("用例失败重连过一次,失败原因:", "../Log/connect64dd15b8-ca91-11e7-87ae-38c98647adce.pickle")
50 | read_reconnect("../Log/connect64dd15b8-ca91-11e7-87ae-38c98647adce.pickle")
51 |
--------------------------------------------------------------------------------
/Base/BaseElementEnmu.py:
--------------------------------------------------------------------------------
1 | class Element(object):
2 |
3 | # selenium关键字
4 | find_element_by_id = "id"
5 | find_elements_by_id = "ids"
6 | INDEX = "index"
7 | find_elements_by_xpath = "xpaths"
8 | find_element_by_xpath = "xpath"
9 | find_element_by_css_selector = "css"
10 | find_element_by_class_name = "class_name"
11 | find_element_by_link_text = "link_text"
12 | CLICK = "click"
13 | GET_TEXT = "get_text"
14 | SEND_KEYS = "send_keys"
15 | GET_VALUE = "get_value"
16 | WAIT_TIME = 20 # 查找元素等待时间
17 | MOVE_TO_ELEMENT = "move_to_element" # 鼠标悬停
18 | DEFAULT_OPERATE= "default_operate" # 默认值
19 |
20 |
21 | # 错误日志
22 | TIME_OUT = "timeout"
23 | NO_SUCH = "noSuch"
24 | WEB_DROVER_EXCEPTION = "WebDriverException"
25 | INDEX_ERROR = "index_error"
26 | STALE_ELEMENT_REFERENCE_EXCEPTION = "StaleElementReferenceException"
27 | DEFAULT_ERROR = "default_error"
28 |
29 | # 检查点
30 | CONTRARY = "contrary" # 相反检查点,表示如果检查元素存在就说明失败,如删除后,此元素依然存在
31 | CONTRARY_GETVAL = "contrary_getval" # 检查点关键字contrary_getval: 相反值检查点,如果对比成功,说明失败
32 | DEFAULT_CHECK = "default_check" # 默认检查点,就是查找页面元素
33 | COMPARE = "compare" # 历史数据和实际数据对比
34 |
35 | RE_CONNECT = 1 # 是否打开失败后再次运行一次用例
36 |
37 | # 文件名字
38 | INFO_FILE = "info.pickle"
39 | SUM_FILE = "sum.pickle"
40 | DEVICES_FILE = "devices.pickle"
41 | REPORT_FILE = "Report.xlsx"
42 |
--------------------------------------------------------------------------------
/Base/BaseRunner.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from Base.BaseLog import myLog
3 | import unittest
4 | from selenium import webdriver
5 | import os
6 | from Base.BaseYaml import getYam
7 |
8 | PATH = lambda p: os.path.abspath(
9 | os.path.join(os.path.dirname(__file__), p)
10 | )
11 |
12 |
13 | def get_driver():
14 | chromedriver = PATH("../exe/chromedriver.exe")
15 | os.environ["webdriver.chrome.driver"] = chromedriver
16 | driver = webdriver.Chrome(chromedriver)
17 | driver.maximize_window() # 将浏览器最大化
18 | openurl = getYam(PATH("../Yamls/config.yaml"))[1]["url"]
19 | driver.get(openurl)
20 | return driver
21 |
22 |
23 | class ParametrizedTestCase(unittest.TestCase):
24 | """ TestCase classes that want to be parametrized should
25 | inherit from this class.
26 | """
27 |
28 | def __init__(self, methodName='runTest', param=None):
29 | super(ParametrizedTestCase, self).__init__(methodName)
30 |
31 | @classmethod
32 | def setUpClass(cls):
33 | pass
34 | cls.driver = get_driver()
35 | cls.logTest = myLog().getLog("chrome") # 每个设备实例化一个日志记录器
36 |
37 | def setUp(self):
38 | pass
39 |
40 | @classmethod
41 | def tearDownClass(cls):
42 | cls.driver.close()
43 | cls.driver.quit()
44 | pass
45 |
46 | def tearDown(self):
47 | pass
48 |
49 | @staticmethod
50 | def parametrize(testcase_klass, param=None):
51 | # print("---parametrize-----")
52 | # print(param)
53 | testloader = unittest.TestLoader()
54 | testnames = testloader.getTestCaseNames(testcase_klass)
55 | suite = unittest.TestSuite()
56 | for name in testnames:
57 | suite.addTest(testcase_klass(name, param=param))
58 | return suite
59 |
--------------------------------------------------------------------------------
/Base/BaseYaml.py:
--------------------------------------------------------------------------------
1 | __author__ = 'shikun'
2 | import yaml
3 | from yaml.scanner import ScannerError
4 | import os
5 |
6 |
7 | # -*- coding:utf-8 -*-
8 | def getYam(path):
9 | try:
10 | with open(path, encoding='utf-8') as f:
11 | x = yaml.load(f)
12 | return [True, x]
13 | except FileNotFoundError:
14 | print("==用例文件不存在==")
15 | app = {'check': [{'element_info': '', 'operate_type': 'get_value', 'find_type': 'ids', 'info': '用例文件不存在'}],
16 | 'testinfo': [{'title': '', 'id': '', 'info': ''}], 'testcase': [{'element_info': '', 'info': '', 'operate_type': '', 'find_type': ''},
17 | {'element_info': '', 'msg': "", 'operate_type': '', 'find_type': '', 'info': ''}, {'element_info': '', 'msg': '', 'operate_type': '', 'find_type': '', 'info': ''},
18 | {'element_info': '', 'info': '', 'operate_type': '', 'find_type': ''}]}
19 |
20 | return [False, app]
21 | except yaml.scanner.ScannerError:
22 | app = {'check': [{'element_info': '', 'operate_type': 'get_value', 'find_type': 'ids', 'info': '用例文件格式错误'}],
23 | 'testinfo': [{'title': '', 'id': '', 'info': ''}],
24 | 'testcase': [{'element_info': '', 'info': '', 'operate_type': '', 'find_type': ''},
25 | {'element_info': '', 'msg': "", 'operate_type': '', 'find_type': '', 'info': ''},
26 | {'element_info': '', 'msg': '', 'operate_type': '', 'find_type': '', 'info': ''},
27 | {'element_info': '', 'info': '', 'operate_type': '', 'find_type': ''}]}
28 | print("==用例格式错误==")
29 | return [False, app]
30 |
31 |
32 | if __name__ == '__main__':
33 |
34 | PATH = lambda p: os.path.abspath(
35 | os.path.join(os.path.dirname(__file__), p)
36 | )
37 | t = getYam(PATH("../Yamls/Home/Login.yaml"))
38 | print(t)
39 |
--------------------------------------------------------------------------------
/Base/BaseEmail.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from email.header import Header
3 | from email.mime.text import MIMEText
4 | from email.utils import parseaddr, formataddr
5 | from email.mime.multipart import MIMEMultipart
6 | from email.mime.application import MIMEApplication
7 | import smtplib
8 | import os
9 | PATH = lambda p: os.path.abspath(
10 | os.path.join(os.path.dirname(__file__), p)
11 | )
12 | def _format_addr(s):
13 | name, addr = parseaddr(s)
14 | return formataddr((Header(name, 'utf-8').encode(), addr))
15 | def send_mail(**kwargs):
16 | '''
17 | :param f: 附件路径
18 | :param to_addr:发给的人 []
19 | :return:
20 | '''
21 | from_addr = kwargs["mail_user"]
22 | password = kwargs["mail_pass"]
23 | # to_addr = "ashikun@126.com"
24 | smtp_server = kwargs["mail_host"]
25 |
26 | msg = MIMEMultipart()
27 |
28 | # msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')
29 | msg['From'] = _format_addr('来自<%s>接口测试' % from_addr)
30 | msg['To'] = _format_addr(' <%s>' % kwargs["to_addr"])
31 | msg['Subject'] = Header(kwargs["header_msg"], 'utf-8').encode()
32 | msg.attach(MIMEText(kwargs["attach"], 'plain', 'utf-8'))
33 |
34 | if kwargs.get("report", "0") != "0":
35 | part = MIMEApplication(open(kwargs["report"], 'rb').read())
36 | part.add_header('Content-Disposition', 'attachment', filename=('gb2312', '', kwargs["report_name"]))
37 | msg.attach(part)
38 |
39 | server = smtplib.SMTP_SSL(smtp_server, kwargs["port"])
40 | server.set_debuglevel(1)
41 | server.login(from_addr, password)
42 | server.sendmail(from_addr, kwargs["to_addr"], msg.as_string())
43 | server.quit()
44 | if __name__ == '__main__':
45 | to_addr = ["284772894@qq.com"]
46 | mail_host = "smtp.qq.com"
47 | mail_user = "284772894@qq.com"
48 | mail_pass = "oftllbhnknegbjhb"
49 | port = "465"
50 | header_msg = "接口测试"
51 | attach = "接口测试"
52 | report = PATH("../Runner/report.xlsx")
53 | send_mail(to_addr = to_addr, mail_host = mail_host, mail_user=mail_user, port=port, mail_pass=mail_pass, header_msg=header_msg, report=report, attach=attach, report_name="接口测试报告")
54 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 项目名及简介
2 | * python3 + selenium自动化测试
3 |
4 | # 介绍
5 | * unittest参数化
6 | * PageObject分层管理
7 | * 用例编写基于yaml配置多关键字驱动
8 | * 自动生成excel测试报告
9 |
10 |
11 |
12 | ## 命令运行
13 |
14 | ```
15 | python runner.py
16 | ```
17 | - 或者修改start.test.bat中的路径后,直接点击运行
18 |
19 |
20 |
21 | # 结果展示
22 |
23 | **日志目录**
24 |
25 | - 文件夹:chrome_XXXXX,包含截图
26 |
27 | ```
28 | 2018-04-29 23:28:09,357 - INFO - ---- test001_登录失败_div.container>ul>li:nth-child(2)_css_click_ ----
29 | 2018-04-29 23:28:09,970 - INFO - ---- test001_登录失败_input-lg_class_name_send_keys_lose1 ----
30 | 2018-04-29 23:28:10,066 - INFO - ---- test001_登录失败_user_password_id_send_keys_1231231232 ----
31 | 2018-04-29 23:28:10,187 - INFO - ---- test001_登录失败_div.form-actions_css_click_ ----
32 | 2018-04-29 23:28:10,784 - INFO - ---- test001_登录失败_div.alert-warning_css_ _ ----
33 | 2018-04-29 23:28:10,785 - INFO - [CheckPoint_1]: testALoginFail_ : OK
34 | 2018-04-29 23:28:36,116 - INFO - ---- test001_登录_div.container>ul>li:nth-child(2)_css_click_ ----
35 | 2018-04-29 23:29:41,881 - INFO - ---- test001_登录_input-lg_class_name_send_keys_lose1 ----
36 | 2018-04-29 23:30:16,331 - INFO - ---- test001_登录_user_password_id_send_keys_1231231232 ----
37 | 2018-04-29 23:30:16,433 - INFO - ---- test001_登录_div.form-actions_css_click_ ----
38 | 2018-04-29 23:31:02,425 - INFO - [CheckPoint_2]: testBLogin_==请检查dropdown-avatar==: NG
39 | ```
40 | - 实时日志
41 |
42 | ```buildoutcfg
43 |
44 | testALoginFail (TestCase.HomeTest.HomeTest) ... ==操作步骤:div.container>ul>li:nth-child(2)_css_click_ ==
45 | ==操作步骤:input-lg_class_name_send_keys_lose1==
46 | ==操作步骤:user_password_id_send_keys_1231231232==
47 | ==操作步骤:div.form-actions_css_click_ ==
48 | ==操作步骤:div.alert-warning_css_ _ ==
49 | ==用例_登录失败检查点成功==
50 | ok
51 | testBLogin (TestCase.HomeTest.HomeTest) ... ==操作步骤:div.container>ul>li:nth-child(2)_css_click_ ==
52 | ==操作步骤:input-lg_class_name_send_keys_lose==
53 | ==操作步骤:user_password_id_send_keys_XXX==
54 | ==操作步骤:div.form-actions_css_click_ ==
55 | ==操作步骤:dropdown-avatar_class_name_click_ ==
56 | ==操作步骤://ul[@class='dropdown-menu']/li/a[contains(text(),'lose')]_xpath_ _ ==
57 | ==用例_登录检查点成功==
58 | [{'caseName': 'testALoginFail', 'step': '点击登录\n输入用户名\n输入密码\n点击登录\n', 'info': '打开testerhome', 'title': '登录失败', 'checkStep': '错误的密码登录不成功\n', 'id': 'test001', 'msg': '', 'name': 'chrome', 'result': '通过'}]
59 | ok
60 | testHotTopic (TestCase.MyTest.MyTest) ... ==操作步骤:div.container>ul>li:nth-child(2)_css_click_ ==
61 | ==操作步骤:input-lg_class_name_send_keys_lose==
62 | ==操作步骤:user_password_id_send_keys_xxxx==
63 | ==操作步骤:div.form-actions_css_click_ ==
64 | ==操作步骤:dropdown-avatar_class_name_click_ ==
65 | ==操作步骤:dropdown-avatar_class_name_click_ ==
66 | ==操作步骤://ul[@class='dropdown-menu']/li/a_xpath_click_ ==
67 | ==操作步骤://ul[@class="list-group"]/li[1]/div/a[2]_xpath_get_text_ ==
68 | ==操作步骤:ul.list-group > li:nth-child(1) > div.title > a:nth-child(2)_css_click_ ==
69 | ==操作步骤:/html/head/title_xpath_get_text_ ==
70 | ==用例_热门话题检查点成功==
71 | ```
72 |
73 |
74 | **测试报告**
75 |
76 | 
77 |
78 | 
79 |
80 | # 其他
81 | * [使用实例](use.md)
82 | * [changelog](CHANGELOG.md)
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/Base/BaseStatistics.py:
--------------------------------------------------------------------------------
1 | import xlsxwriter
2 |
3 | from Base.BaseElementEnmu import Element
4 | from Base.BaseExcel import OperateReport
5 | from Base.BaseInit import destroy
6 | from Base.BasePickle import *
7 | from datetime import datetime
8 |
9 | PATH = lambda p: os.path.abspath(
10 | os.path.join(os.path.dirname(__file__), p)
11 | )
12 |
13 | '''
14 | 统计数据相关
15 | '''
16 |
17 | '''
18 | result bool
19 | logTest 记录日志类 class
20 | driver
21 | testinfo
22 |
23 | '''
24 |
25 |
26 | def countInfo(**kwargs):
27 | _info = {}
28 | step = "" # 操作步骤信息
29 | check_step = "" # 检查点步骤信息
30 |
31 | for case in kwargs["testCase"]:
32 | step = step + case["info"] + "\n"
33 |
34 | if type(kwargs["testCheck"]) == list: # 检查点为列表
35 | for check in kwargs["testCheck"]:
36 | check_step = check_step + check["info"] + "\n"
37 | elif type(kwargs["testCheck"]) == dict:
38 | check_step = kwargs["testCheck"]["info"]
39 | else:
40 | print("获取检查点步骤数据错误,请检查")
41 | print(kwargs["testCheck"])
42 |
43 | _info["step"] = step # 用例操作步骤
44 | _info["checkStep"] = check_step # 用例检查点
45 |
46 | if kwargs["result"]:
47 | _info["result"] = "通过"
48 | kwargs["logTest"].checkPointOK(driver=kwargs["driver"], caseName=kwargs["testInfo"][0]["title"],
49 | checkPoint=kwargs["caseName"] + "_" + kwargs["testInfo"][0].get(
50 | "msg", " "))
51 | else:
52 | _info["result"] = "失败" # 用例接开关
53 | _info["img"] = kwargs["logTest"].checkPointNG(driver=kwargs["driver"], caseName=kwargs["testInfo"][0]["title"],
54 | checkPoint=kwargs["caseName"] + "_" + kwargs["testInfo"][0].get(
55 | "msg", " "))
56 | _info["id"] = kwargs["testInfo"][0]["id"] # 用例id
57 | _info["title"] = kwargs["testInfo"][0]["title"] # 用例名称
58 | _info["caseName"] = kwargs["caseName"] # 测试函数
59 | _info["name"] = kwargs["name"] # 设备名
60 | _info["msg"] = kwargs["testInfo"][0].get("msg", "") # 备注
61 | _info["info"] = kwargs["testInfo"][0]["info"] # 前置条件
62 |
63 | writeInfo(data=_info, path=PATH("../Log/" + Element.INFO_FILE))
64 | # print(read(PATH("../Log/info.pickle")))
65 |
66 |
67 | # 统计所有用例数
68 | def countSum(result):
69 | # print("----countSum----")
70 | data = {"sum": 0, "pass": 0, "fail": 0}
71 | _read = read(PATH("../Log/sum.pickle"))
72 | if _read:
73 | data = _read
74 | data["sum"] += 1
75 | if result:
76 | data["pass"] += 1
77 | else:
78 | data["fail"] += 1
79 | write(data=data, path=PATH("../Log/" + Element.SUM_FILE))
80 | # print(read(PATH("../Log/sum.pickle")))
81 |
82 |
83 | def countDate(testDate, testSumDate):
84 | data = read(PATH("../Log/" + Element.SUM_FILE))
85 | if data:
86 | data["testDate"] = testDate
87 | data["testSumDate"] = testSumDate
88 | write(data=data, path=PATH("../Log/" + Element.SUM_FILE))
89 | else:
90 | print("统计数据失败")
91 | data = read(PATH("../Log/" + Element.SUM_FILE))
92 | print("==统计数据:%s==" % data)
93 |
94 |
95 | '''
96 | 测试报告
97 | '''
98 |
99 |
100 | def writeExcel():
101 | workbook = xlsxwriter.Workbook(PATH('../Report/' + Element.REPORT_FILE))
102 | worksheet = workbook.add_worksheet("测试总况")
103 | worksheet2 = workbook.add_worksheet("测试详情")
104 | operateReport = OperateReport(workbook)
105 | operateReport.init(worksheet, read(PATH("../Log/" + Element.SUM_FILE)))
106 | operateReport.detail(worksheet2, readInfo(PATH("../Log/" + Element.INFO_FILE)))
107 | operateReport.close()
108 |
109 | # destroy() # 删除文件
110 |
111 |
112 | if __name__ == '__main__':
113 | # data = {'result': '失败', 'caseName': 'FirstOpenTest', 'title': '第一次打开', 'phoneName': 'samsung_GT-I9500_android_4.4.2', 'img': 'D:\\app\\appium\\log\\samsung_GT-I9500_android_4.4.220170607184558\\第一次打开CheckPoint_1_NG.png', 'id': 'test001'}
114 | # writeInfo(data, PATH("../Log/info.pickle"))
115 | # writeInfo(data, PATH("../Log/info.pickle"))
116 | # _read = readInfo(PATH("../Log/info.pickle"))
117 | writeExcel()
118 |
--------------------------------------------------------------------------------
/PageObject/Pages.py:
--------------------------------------------------------------------------------
1 | from Base.BaseYaml import getYam
2 | from Base.BaseOperate import OperateElement
3 | import time
4 | from Base.BaseElementEnmu import Element as be
5 | import os
6 | from PageObject.SumResult import statistics_result
7 | from Base.BaseError import get_error
8 |
9 | PATH = lambda p: os.path.abspath(
10 | os.path.join(os.path.dirname(__file__), p)
11 | )
12 |
13 |
14 | class PagesObjects:
15 | '''
16 | page层
17 | kwargs: WebDriver driver, String path(yaml配置参数)
18 | isOperate: 操作失败,检查点就失败
19 | testInfo:
20 | testCase:
21 | '''
22 |
23 | def __init__(self, kwargs):
24 | self.driver = kwargs["driver"]
25 |
26 | if kwargs.get("launch", "0") == "0": # 若为空, 刷新页面
27 | self.driver.get(self.driver.current_url)
28 | self.operateElement = ""
29 | self.isOperate = True
30 | self.test_msg = kwargs["test_msg"]
31 | self.testInfo = self.test_msg[1]["testinfo"]
32 | self.testCase = self.test_msg[1]["testcase"]
33 | self.test_check = self.test_msg[1]["check"]
34 | self.logTest = kwargs["logTest"]
35 | self.caseName = kwargs["caseName"]
36 | self.get_value = []
37 | self.is_get = False # 检查点特殊标志,结合get_value使用。若为真,说明检查点要对比历史数据和实际数据
38 | self.msg = ""
39 |
40 | '''
41 | 操作步骤
42 | '''
43 |
44 | def operate(self):
45 |
46 | if self.test_msg[0] is False:
47 | self.isOperate = False
48 | return False
49 | self.operateElement = OperateElement(self.driver)
50 | for item in self.testCase:
51 | result = self.operateElement.operate(item, self.testInfo, self.logTest)
52 | if not result["result"]:
53 | msg = get_error({"type": be.DEFAULT_ERROR, "element_info": item["element_info"]})
54 | print(msg)
55 | self.testInfo[0]["msg"] = msg
56 | self.isOperate = False
57 | return False
58 | if item.get("is_time", "0") != "0":
59 | time.sleep(item["is_time"]) # 等待时间
60 | print("==等待%s秒==" % item["is_time"])
61 | if item.get("operate_type", "0") == be.GET_VALUE or item.get("operate_type", "0") == be.GET_TEXT:
62 | self.get_value.append(result["text"])
63 | self.is_get = True # 对比数据
64 |
65 | return True
66 |
67 | def checkPoint(self, kwargs={}):
68 | result = self.check(kwargs)
69 | statistics_result(result=result, testInfo=self.testInfo, caseName=self.caseName,
70 | driver=self.driver, logTest=self.logTest,
71 | testCase=self.testCase,
72 | testCheck=self.test_check)
73 |
74 | '''
75 | 检查点
76 | caseName:测试用例函数名 用作统计
77 | logTest: 日志记录
78 | '''
79 |
80 | def check(self, kwargs):
81 | result = True
82 | # if kwargs.get("check_point", "0") != "0":
83 | # return kwargs["check_point"]
84 |
85 | if self.isOperate:
86 | for item in self.test_check:
87 |
88 | resp = self.operateElement.operate(item, self.testInfo, self.logTest)
89 | # 默认检查点,就是查找页面元素
90 | if kwargs.get("check", be.DEFAULT_CHECK) == be.DEFAULT_CHECK and not resp["result"]:
91 | m = get_error({"type": be.DEFAULT_CHECK, "element_info": item["element_info"], "info": item["info"]})
92 | print(m)
93 | self.testInfo[0]["msg"] = m
94 | result = False
95 | break
96 | # 历史数据和实际数据对比
97 | if kwargs.get("check", be.DEFAULT_CHECK) == be.COMPARE and self.is_get and resp["text"]\
98 | not in self.get_value: # 历史数据和实际数据对比
99 | result = False
100 | m = get_error({"type": be.COMPARE, "current": item["element_info"], "history": resp["text"]})
101 | print(m)
102 | self.testInfo[0]["msg"] = m
103 | break
104 | # 相反检查点,表示如果检查元素存在就说明失败,如删除后,此元素依然存在
105 | if kwargs.get("check", be.DEFAULT_CHECK) == be.CONTRARY and resp["result"]:
106 | m = get_error({"type": be.CONTRARY, "element_info": item["element_info"], "info": item["info"]})
107 | print(m)
108 | self.testInfo[0]["msg"] = m
109 | result = False
110 | break
111 | # 检查点关键字contrary_getval: 相反值检查点,如果对比成功,说明失败
112 | if kwargs.get("check", be.DEFAULT_CHECK) == be.CONTRARY_GETVAL and self.is_get and resp["result"] \
113 | in self.get_value:
114 | m = get_error(
115 | {"type": be.CONTRARY_GETVAL, "current": item["element_info"], "history": resp["text"]})
116 | print(m)
117 | self.testInfo[0]["msg"] = m
118 | result = False
119 | break
120 |
121 | else:
122 | result = False
123 | return result
124 |
--------------------------------------------------------------------------------
/Base/BaseLog.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import time
3 | import os
4 | from time import sleep
5 | import threading
6 |
7 | PATH = lambda p: os.path.abspath(
8 | os.path.join(os.path.dirname(__file__), p)
9 | )
10 |
11 |
12 | class Log:
13 | def __init__(self, name):
14 | phone_name = name
15 | global logger, resultPath, logPath
16 | resultPath = PATH("../log")
17 | logPath = os.path.join(resultPath, (phone_name + time.strftime('%Y%m%d%H%M%S', time.localtime())))
18 | if not os.path.exists(logPath):
19 | os.makedirs(logPath)
20 | self.checkNo = 0
21 | self.logger = logging.getLogger()
22 | self.logger.setLevel(logging.INFO)
23 |
24 | # create handler,write log
25 | fh = logging.FileHandler(os.path.join(logPath, "outPut.log"))
26 | # Define the output format of formatter handler
27 | formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
28 | fh.setFormatter(formatter)
29 |
30 | self.logger.addHandler(fh)
31 |
32 | def getMyLogger(self):
33 | """get the logger
34 | :return:logger
35 | """
36 | return self.logger
37 |
38 | def buildStartLine(self, caseNo):
39 | """build the start log
40 | :param caseNo:
41 | :return:
42 | """
43 | startLine = "---- " + caseNo + " " + " " + \
44 | " ----"
45 | # startLine = "---- " + caseNo + " " + "START" + " " + \
46 | # " ----"
47 | self.logger.info(startLine)
48 |
49 | def buildEndLine(self, caseNo):
50 | """build the end log
51 | :param caseNo:
52 | :return:
53 | """
54 | endLine = "---- " + caseNo + " " + "END" + " " + \
55 | " ----"
56 | self.logger.info(endLine)
57 | self.checkNo = 0
58 |
59 | def writeResult(self, result):
60 | """write the case result(OK or NG)
61 | :param result:
62 | :return:
63 | """
64 | reportPath = os.path.join(logPath, "report.txt")
65 | flogging = open(reportPath, "a")
66 | try:
67 | flogging.write(result + "\n")
68 | finally:
69 | flogging.close()
70 | pass
71 |
72 | def resultOK(self, caseNo):
73 | self.writeResult(caseNo + ": OK")
74 |
75 | def resultNG(self, caseNo, reason):
76 | self.writeResult(caseNo + ": NG--" + reason)
77 |
78 | def checkPointOK(self, driver, caseName, checkPoint):
79 | """write the case's checkPoint(OK)
80 | :param driver:
81 | :param caseName:
82 | :param checkPoint:
83 | :return:
84 | """
85 | self.checkNo += 1
86 |
87 | self.logger.info("[CheckPoint_" + str(self.checkNo) + "]: " + checkPoint + ": OK")
88 | print("==用例_%s检查点成功==" % caseName)
89 |
90 | # take shot 默认去掉成功截图
91 | # self.screenshotOK(driver, caseName)
92 |
93 | def checkPointNG(self, driver, caseName, checkPoint):
94 | """write the case's checkPoint(NG)
95 | :param driver:
96 | :param caseName:
97 | :param checkPoint:
98 | :return:
99 | """
100 | self.checkNo += 1
101 |
102 | self.logger.info("[CheckPoint_" + str(self.checkNo) + "]: " + checkPoint + ": NG")
103 | # take shot
104 | return self.screenshotNG(driver, caseName)
105 |
106 | def screenshotOK(self, driver, caseName):
107 | """screen shot
108 | :param driver:
109 | :param caseName:
110 | :return:
111 | """
112 | screenshotPath = os.path.join(logPath, caseName)
113 | screenshotName = "CheckPoint_" + str(self.checkNo) + "_OK.png"
114 |
115 | # wait for animations to complete before taking screenshot
116 | sleep(1)
117 | # driver.get_screenshot_as_file(os.path.join(screenshotPath, screenshotName))
118 | driver.get_screenshot_as_file(os.path.join(screenshotPath + screenshotName))
119 |
120 | def screenshotNG(self, driver, caseName):
121 | """screen shot
122 | :param driver:
123 | :param caseName:
124 | :return:
125 | """
126 | screenshotPath = os.path.join(logPath, caseName)
127 | screenshotName = "CheckPoint_" + str(self.checkNo) + "_NG.png"
128 |
129 | # wait for animations to complete before taking screenshot
130 | sleep(1)
131 | driver.get_screenshot_as_file(os.path.join(screenshotPath + screenshotName))
132 | return os.path.join(screenshotPath + screenshotName)
133 |
134 | def screenshotERROR(self, driver, caseName):
135 | """screen shot
136 | :param driver:
137 | :param caseName:
138 | :return:
139 | """
140 | screenshotPath = os.path.join(logPath, caseName)
141 | screenshotName = "ERROR.png"
142 |
143 | # wait for animations to complete before taking screenshot
144 | sleep(1)
145 | driver.get_screenshot_as_file(os.path.join(screenshotPath, screenshotName))
146 |
147 |
148 | class myLog:
149 | """
150 | This class is used to get log
151 | """
152 |
153 | log = None
154 | mutex = threading.Lock()
155 |
156 | def __init__(self):
157 | pass
158 |
159 | @staticmethod
160 | def getLog(devices):
161 | if myLog.log is None:
162 | myLog.mutex.acquire()
163 | myLog.log = Log(devices)
164 | myLog.mutex.release()
165 |
166 | return myLog.log
167 |
168 |
169 | if __name__ == "__main__":
170 | logTest = myLog.getLog("devices")
171 | # logger = logTest.getMyLogger()
172 | logTest.buildStartLine("11111111111111111111111")
--------------------------------------------------------------------------------
/Base/BaseExcel.py:
--------------------------------------------------------------------------------
1 | __author__ = 'shikun'
2 | import xlsxwriter
3 | import os
4 |
5 | PATH = lambda p: os.path.abspath(
6 | os.path.join(os.path.dirname(__file__), p)
7 | )
8 |
9 |
10 | class OperateReport:
11 | def __init__(self, wd):
12 | self.wd = wd
13 |
14 | def init(self, worksheet, data):
15 | # 设置列行的宽高
16 | worksheet.set_column("A:A", 15)
17 | worksheet.set_column("B:B", 20)
18 | worksheet.set_column("C:C", 20)
19 | worksheet.set_column("D:D", 20)
20 |
21 | worksheet.set_row(1, 30)
22 | worksheet.set_row(2, 30)
23 | worksheet.set_row(3, 30)
24 | worksheet.set_row(4, 30)
25 |
26 | define_format_H1 = get_format(self.wd, {'bold': True, 'font_size': 18})
27 | define_format_H2 = get_format(self.wd, {'bold': True, 'font_size': 14})
28 | define_format_H1.set_border(1)
29 |
30 | define_format_H2.set_border(1)
31 | define_format_H1.set_align("center")
32 | define_format_H2.set_align("center")
33 | define_format_H2.set_bg_color("blue")
34 | define_format_H2.set_color("#ffffff")
35 |
36 | worksheet.merge_range('A1:D1', '测试报告总概况', define_format_H1)
37 | worksheet.merge_range('A2:D2', 'XXXX项目', define_format_H2)
38 |
39 | _write_center(worksheet, "A3", '测试日期', self.wd)
40 | _write_center(worksheet, "A4", '耗时', self.wd)
41 | _write_center(worksheet, "A5", '总用例', self.wd)
42 |
43 | _write_center(worksheet, "B3", data['testDate'], self.wd)
44 | _write_center(worksheet, "B4", data['testSumDate'], self.wd)
45 | _write_center(worksheet, "B5", data['sum'], self.wd)
46 |
47 | _write_center(worksheet, "C3", "通过", self.wd)
48 | _write_center(worksheet, "C4", "失败", self.wd)
49 | _write_center(worksheet, "C5", "脚本版本", self.wd)
50 |
51 | _write_center(worksheet, "D3", data['pass'], self.wd)
52 | _write_center(worksheet, "D4", data['fail'], self.wd)
53 | _write_center(worksheet, "D5", data['version'], self.wd)
54 |
55 | pie(self.wd, worksheet)
56 |
57 | def detail(self, worksheet, info):
58 | # 设置列行的宽高
59 | worksheet.set_column("A:A", 30)
60 | worksheet.set_column("B:B", 20)
61 | worksheet.set_column("C:C", 20)
62 | worksheet.set_column("D:D", 20)
63 | worksheet.set_column("E:E", 20)
64 | worksheet.set_column("F:F", 20)
65 | worksheet.set_column("G:G", 20)
66 | worksheet.set_column("H:H", 20)
67 | worksheet.set_column("I:I", 20)
68 | worksheet.set_column("J:J", 20)
69 |
70 | worksheet.set_row(1, 30)
71 | worksheet.set_row(2, 30)
72 | worksheet.set_row(3, 30)
73 | worksheet.set_row(4, 30)
74 | worksheet.set_row(5, 30)
75 | worksheet.set_row(6, 30)
76 | worksheet.set_row(7, 30)
77 | worksheet.set_row(8, 30)
78 | worksheet.set_row(9, 30)
79 | worksheet.set_row(10, 30)
80 |
81 | worksheet.merge_range('A1:J1', '测试详情', get_format(self.wd, {'bold': True, 'font_size': 18, 'align': 'center',
82 | 'valign': 'vcenter', 'bg_color': 'blue',
83 | 'font_color': '#ffffff'}))
84 | _write_center(worksheet, "A2", '设备', self.wd)
85 | _write_center(worksheet, "B2", '用例ID', self.wd)
86 | _write_center(worksheet, "C2", '用例介绍', self.wd)
87 | _write_center(worksheet, "D2", '用例函数', self.wd)
88 | _write_center(worksheet, "E2", '前置条件', self.wd)
89 | _write_center(worksheet, "F2", '操作步骤 ', self.wd)
90 | _write_center(worksheet, "G2", '检查点 ', self.wd)
91 | _write_center(worksheet, "H2", '测试结果 ', self.wd)
92 | _write_center(worksheet, "I2", '截图', self.wd)
93 |
94 | temp = 3
95 | for item in info:
96 | _write_center(worksheet, "A" + str(temp), item["name"], self.wd)
97 | _write_center(worksheet, "B" + str(temp), item["id"], self.wd)
98 | _write_center(worksheet, "C" + str(temp), item["title"], self.wd)
99 | _write_center(worksheet, "D" + str(temp), item["caseName"], self.wd)
100 | _write_center(worksheet, "E" + str(temp), item["info"], self.wd)
101 | _write_center(worksheet, "F" + str(temp), item["step"], self.wd)
102 | _write_center(worksheet, "G" + str(temp), item["checkStep"], self.wd)
103 | _write_center(worksheet, "H" + str(temp), item["result"], self.wd)
104 | if item.get("img", "false") == "false":
105 | _write_center(worksheet, "I" + str(temp), "", self.wd)
106 | worksheet.set_row(temp, 30)
107 | else:
108 | worksheet.insert_image('J' + str(temp), item["img"],
109 | {'x_scale': 0.1, 'y_scale': 0.1, 'border': 1})
110 | worksheet.set_row(temp - 1, 110)
111 | temp += 1
112 |
113 | def close(self):
114 | self.wd.close()
115 |
116 |
117 | def get_format(wd, option={}):
118 | return wd.add_format(option)
119 |
120 |
121 | def get_format_center(wd, num=1):
122 | return wd.add_format({'align': 'center', 'valign': 'vcenter', 'border': num})
123 |
124 |
125 | def set_border_(wd, num=1):
126 | return wd.add_format({}).set_border(num)
127 |
128 |
129 | def _write_center(worksheet, cl, data, wd):
130 | return worksheet.write(cl, data, get_format_center(wd))
131 |
132 |
133 | def set_row(worksheet, num, height):
134 | worksheet.set_row(num, height)
135 |
136 | # 生成饼形图
137 |
138 |
139 | def pie(workbook, worksheet):
140 | chart1 = workbook.add_chart({'type': 'pie'})
141 | chart1.add_series({
142 | 'name': '自动化测试统计',
143 | 'categories': '=测试总况!$C$3:$C$4',
144 | 'values': '=测试总况!$D$3:$D$4',
145 | })
146 | chart1.set_title({'name': '测试统计'})
147 | chart1.set_style(10)
148 | worksheet.insert_chart('A9', chart1, {'x_offset': 25, 'y_offset': 10})
149 |
150 |
151 | if __name__ == '__main__':
152 | pass
153 |
--------------------------------------------------------------------------------
/Base/BaseOperate.py:
--------------------------------------------------------------------------------
1 |
2 | # -*- coding: utf-8 -*-
3 | from selenium.webdriver.support.ui import WebDriverWait
4 | import selenium.common.exceptions
5 | from Base.BaseElementEnmu import Element as be
6 | from selenium.webdriver.common.action_chains import *
7 | import time
8 | import re
9 |
10 | '''
11 | # 此脚本主要用于查找元素是否存在,操作页面元素
12 | '''
13 |
14 |
15 | class OperateElement:
16 | def __init__(self, driver=""):
17 | self.driver = driver
18 |
19 | def findElement(self, operate):
20 | '''
21 | 查找元素.operate,dict|list
22 | operate_type:对应的操作
23 | element_info:元素详情
24 | find_type: find类型
25 | '''
26 | try:
27 | t = operate["check_time"] if operate.get("check_time",
28 | "0") != "0" else be.WAIT_TIME # 如果自定义检测时间为空,就用默认的检测等待时间
29 | if type(operate) == list: # 多检查点
30 | for item in operate:
31 | t = item["check_time"] if item.get("check_time", "0") != "0" else be.WAIT_TIME
32 | WebDriverWait(self.driver, t).until(lambda x: self.elements_by(item))
33 | return {"result": True}
34 | if type(operate) == dict: # 单检查点
35 | if operate.get("element_info", "0") == "0": # 如果没有页面元素,就不检测是页面元素,可能是滑动等操作
36 | return {"result": True}
37 | WebDriverWait(self.driver, t).until(lambda x: self.elements_by(operate)) # 操作元素是否存在
38 | return {"result": True}
39 | except selenium.common.exceptions.TimeoutException:
40 | # print("==查找元素超时==")
41 | return {"result": False, "type": be.TIME_OUT}
42 | except selenium.common.exceptions.NoSuchElementException:
43 | # print("==查找元素不存在==")
44 | return {"result": False, "type": be.NO_SUCH}
45 | except selenium.common.exceptions.WebDriverException:
46 | # print("WebDriver出现问题了")
47 | return {"result": False, "type": be.WEB_DROVER_EXCEPTION}
48 |
49 | '''
50 | 查找元素.mOperate是字典:operate_type,element_info,find_type:
51 | testInfo: 用例介绍
52 | logTest: 记录日志
53 | '''
54 |
55 | def operate(self, operate, testInfo, logTest):
56 | res = self.findElement(operate)
57 | if res["result"]:
58 | return self.operate_by(operate, testInfo, logTest)
59 | else:
60 | return res
61 |
62 | def operate_by(self, operate, testInfo, logTest):
63 | try:
64 | info = "%s_%s_%s_%s" % (
65 | operate.get("element_info", " "), operate.get("find_type"), operate.get("operate_type", " "),
66 | operate.get("msg", " "))
67 | print("==操作步骤:%s==" % info)
68 | logTest.buildStartLine(testInfo[0]["id"] + "_" + testInfo[0]["title"] + "_" + info) # 记录日志
69 |
70 | if operate.get("operate_type", "0") == "0": # 如果没有此字段,说明没有相应操作,一般是检查点,直接判定为成功
71 | return {"result": True}
72 | elements = {
73 | be.CLICK: lambda: self.click(operate),
74 | be.GET_VALUE: lambda: self.get_value(operate),
75 | be.GET_TEXT: lambda: self.get_text(operate),
76 | be.SEND_KEYS: lambda: self.send_keys(operate),
77 | be.MOVE_TO_ELEMENT: lambda: self.move_to_element(operate)
78 |
79 | }
80 | return elements[operate.get("operate_type")]()
81 | except IndexError:
82 | logTest.buildStartLine(
83 | testInfo[0]["id"] + "_" + testInfo[0]["title"] + "_" + operate["element_info"] + "索引错误") # 记录日志
84 | # print(operate["element_info"] + "索引错误")
85 | return {"result": False, "type": be.INDEX_ERROR}
86 |
87 | except selenium.common.exceptions.NoSuchElementException:
88 | logTest.buildStartLine(
89 | testInfo[0]["id"] + "_" + testInfo[0]["title"] + "_" + operate[
90 | "element_info"] + "页面元素不存在或没加载完成") # 记录日志
91 | # print(operate["element_info"] + "页面元素不存在或没有加载完成")
92 | return {"result": False, "type": be.NO_SUCH}
93 | except selenium.common.exceptions.StaleElementReferenceException:
94 | logTest.buildStartLine(
95 | testInfo[0]["id"] + "_" + testInfo[0]["title"] + "_" + operate[
96 | "element_info"] + "页面元素已经变化") # 记录日志
97 | # print(operate["element_info"] + "页面元素已经变化")
98 | return {"result": False, "type": be.STALE_ELEMENT_REFERENCE_EXCEPTION}
99 | except KeyError:
100 | # 如果key不存在,一般都是在自定义的page页面去处理了,这里直接返回为真
101 | return {"result": True}
102 |
103 | # 点击事件
104 | def click(self, operate):
105 | # print(self.driver.page_source)
106 | if operate["find_type"] == be.find_element_by_id or operate["find_type"] == be.find_element_by_xpath \
107 | or be.find_element_by_css_selector or operate["find_type"] == be.find_element_by_class_name or \
108 | operate["find_type"] == be.find_element_by_link_text:
109 | self.elements_by(operate).click()
110 | elif operate.get("find_type") == be.find_elements_by_id:
111 | self.elements_by(operate)[operate["index"]].click()
112 | return {"result": True}
113 |
114 | def send_keys(self, operate):
115 | """
116 | :param operate:
117 | :return:
118 | """
119 | time.sleep(0.5)
120 | self.elements_by(operate).send_keys(operate["msg"])
121 | return {"result": True}
122 |
123 | def get_text(self, operate):
124 | '''
125 | :param operate:
126 | :return: {}
127 | '''
128 |
129 | if operate.get("find_type") == be.find_elements_by_id:
130 | element_info = self.elements_by(operate)[operate["index"]]
131 |
132 | result = element_info.get_attribute("text")
133 | re_reulst = re.findall(r'[a-zA-Z\d+\u4e00-\u9fa5]', result) # 只匹配中文,大小写,字母
134 | return {"result": True, "text": "".join(re_reulst)}
135 |
136 | element_info = self.elements_by(operate)
137 | result = element_info.get_attribute("text")
138 |
139 | re_reulst = re.findall(r'[a-zA-Z\d+\u4e00-\u9fa5]', result)
140 | return {"result": True, "text": "".join(re_reulst)}
141 |
142 | def get_value(self, operate):
143 | if operate.get("find_type") == be.find_elements_by_id:
144 | element_info = self.elements_by(operate)[operate["index"]]
145 |
146 | result = element_info.get_attribute("value")
147 | re_reulst = re.findall(r'[a-zA-Z\d+\u4e00-\u9fa5]', result) # 只匹配中文,大小写,字母
148 | return {"result": True, "text": "".join(re_reulst)}
149 |
150 | element_info = self.elements_by(operate)
151 | result = element_info.get_attribute("value")
152 |
153 | re_reulst = re.findall(r'[a-zA-Z\d+\u4e00-\u9fa5]', result)
154 | return {"result": True, "text": "".join(re_reulst)}
155 | '''
156 | 鼠标悬停
157 | '''
158 | def move_to_element(self, operate):
159 | ActionChains(self.driver).move_to_element(self.elements_by(operate)).perform()
160 | return {"result": True}
161 |
162 | # 封装常用的标签
163 | def elements_by(self, operate):
164 | elements = {
165 | be.find_element_by_id: lambda: self.driver.find_element_by_id(operate["element_info"]),
166 | be.find_element_by_xpath: lambda: self.driver.find_element_by_xpath(operate["element_info"]),
167 | be.find_element_by_class_name: lambda: self.driver.find_element_by_class_name(operate['element_info']),
168 | be.find_elements_by_id: lambda: self.driver.find_elements_by_id(operate['element_info']),
169 | be.find_element_by_css_selector: lambda: self.driver.find_element_by_css_selector(operate['element_info']),
170 | be.find_element_by_link_text: lambda: self.driver.find_element_by_link_text(operate['element_info'])
171 |
172 | }
173 | return elements[operate["find_type"]]()
174 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
119 |
120 |
121 |
122 | //*[@id="applyContinue"]/div/div/div/div[4]/div/textarea
123 | GetAppCase
124 | workbook
125 | ro
126 | root
127 |
128 |
129 | webcase
130 | self.wd
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 | 1492738167267
534 |
535 |
536 | 1492738167267
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
--------------------------------------------------------------------------------