[TOC]
UI自动化和接口自动化框架的设计思路大同小异,主要目的还是分离业务代码和测试数据,达到代码的复用,提高测试用例的可维护性以及最最重要的减少人工劳动力。
**框架目录结构:**
![](https://img.kancloud.cn/6d/09/6d090eea379982b050a72710db9d5ee1_261x228.png)
```
case:存放具体的测试代码
comm:存放共通的方法
file:存放测试用例等测试过程中用到的测试数据
result:每次测试的log和测试报告的存放位置
caseList:规定执行哪些测试
config:配置静态数据
readConfig:读取config文件内容
runAll:测试执行入口文件
```
首先,要保证你的python已经安装了selenium包,如果你是用pip来管理自己的python环境的,那么你可以通过下面的命令来导入selenium模块:
`pip install selenium`
然后,你需要到网上去下载对应浏览器的驱动,这里小编使用的是chrome浏览器,(chrome下载地址:http://chromedriver.storage.googleapis.com/index.html)。下载完成之后呢,将下载的浏览器驱动放到本地的python安装目录下,这样就可以直接在框架中使用了。至此,必备的条件都有了,我们就可以开工啦。
这里呢,我们就只挑部分内容进行讲解,有许多跟接口测试框架相同或相似的方法和文件,就不一一进行二次说明了,第一次看的盆友们,有不明白的地方可以看这篇文章,进行补充学习
**打开浏览器:**
```
from selenium import webdriver
class Driver:
def __init__(self):
self.browser = webdriver.Chrome()
def open_browser(self):
"""
Do something for browser
:return: browser
"""
# 窗口最大化
self.browser.maximize_window()
# 打开地址链接
url = 'http://www.baidu.com'
self.browser.get(url)
return self.browser
def close_browser(self):
"""
quit browser
:return:
"""
self.browser.quit()
```
从上面的代码可以看出,我们进行了打开/关闭浏览器的方法定义,只有简单的几行代码,当然了,这里为了方便大家观看,我把url地址直接写了出来,在实际操作时,我们可以将其抽离出来,根据自己的需要,传入不同的url地址。这就留着让大家去自己实现吧。
**一个搜索例子:**
```
# -*- coding: utf-8 -*-
from time import sleep
from selenium import webdriver
import unittest
class Login(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
# 窗口最大化
self.driver.maximize_window()
self.msg = '海贼王'
self.url = "http://www.baidu.com"
def testSearch(self):
'''
test body
:return:
'''
# open browser
self.driver.get(self.url)
sleep(3)
# click search input
self.driver.find_element_by_id('kw').click()
sleep(1)
# input value
self.driver.find_element_by_id('kw').send_keys(self.msg)
sleep(1)
self.driver.find_element_by_id('su').click()
sleep(1)
def tearDown(self):
self.driver.close()
if __name__ == "__main__":
unittest.main()
```
**添加log日志:**
在上面的基础上,我们可以添加执行时输出的log日志。所以开始写log文件,并将它放在comm文件夹下,作为共同方法来用。这部分内容在接口测试框架那里已经介绍过了,所以请还不清楚的朋友们移步此处:[]()
**抽离出浏览器的相关操作:**
我们可以将对浏览器的操作剥离出来,单独放到一个文件中,这样既清晰,又避免了重复的代码操作。而且维护起来也比较方便。
```
from selenium import webdriver
from comm.Log import MyLog as Log
import readConfig
import threading
localReadConfig = readConfig.ReadConfig()
class Driver:
def __init__(self):
self.log = Log.get_log()
self.logger = self.log.get_logger()
self.browser = webdriver.Chrome()
def open_browser(self, name1, name2):
"""
Do something for browser
:return: browser
"""
self.logger.info("Open browser")
# 窗口最大化
self.browser.maximize_window()
# 打开地址链接
url = localReadConfig.get_webServer(name1, name2)
self.browser.get(url)
return self.browser
def close_browser(self):
"""
quit browser
:return:
"""
self.browser.quit()
self.logger.info("Quit browser")
def get_driver(self):
"""
get web driver
:return:
"""
return self.browser
class MyDriver:
driver = None
mutex = threading.Lock()
def __init__(self):
pass
@staticmethod
def get_browser():
if MyDriver.driver is None:
MyDriver.mutex.acquire()
MyDriver.driver = Driver()
MyDriver.mutex.release()
return MyDriver.driver
if __name__ == "__main__":
driver = MyDriver.browser()
browser = driver.open_browser()
```
以上便是剥离出来的部分,并且将它放到了单独的线程中。
**关于Element的那些事儿:**
做过UI功能测试的朋友们应该都知道,元素是我们测试最基本也是最重要的东西,以为它是我们直接的操作对象,所以,处理好它们,我们就会省掉很多的麻烦,所以呢,接下来,将会继续分享自己处理element的一些方法。
```
class Element:
def __init__(self, activity_name, element_name):
self.driver1 = Driver.get_browser()
self.driver = self.driver1.get_driver()
self.activity = activity_name
self.element = element_name
element_dict = get_el_dict(self.activity, self.element)
self.pathType = element_dict.get('pathType')
self.pathValue = element_dict.get('pathValue')
def is_exist(self):
"""
Determine element is exist
:return: TRUE OR FALSE
"""
try:
if self.pathType == 'ID':
self.driver.find_element_by_id(self.pathValue)
return True
if self.pathType == 'XPATH':
self.driver.find_elements_by_xpath(self.pathValue)
return True
if self.pathType == 'CLASSNAME':
self.driver.find_element_by_class_name(self.pathValue)
return True
if self.pathType == 'NAME':
self.driver.find_element_by_name(self.pathValue)
return True
except NoSuchElementException:
return False
def wait_element(self, wait_time):
"""
wait element appear in time
:param wait_time: wait time
:return: true or false
"""
time.sleep(wait_time)
if self.is_exist():
return True
else:
return False
def get_element(self):
"""
get element
:return: element
"""
try:
if self.pathType == 'ID':
element = self.driver.find_element_by_id(self.pathValue)
return element
if self.pathType == 'XPATH':
element = self.driver.find_elements_by_xpath(self.pathValue)
return element
if self.pathType == 'CLASSNAME':
element = self.driver.find_element_by_class_name(self.pathValue)
return element
if self.pathType == 'NAME':
element = self.driver.find_element_by_name(self.pathValue)
return element
except NoSuchElementException:
return None
def get_element_by_index(self, index):
"""
get element by index
:param index: index
:return: element
"""
try:
if self.pathType == 'ID':
element = self.driver.find_element_by_id(self.pathValue)
return element[index]
if self.pathType == 'XPATH':
element = self.driver.find_elements_by_xpath(self.pathValue)
return element[index]
if self.pathType == 'CLASSNAME':
element = self.driver.find_element_by_class_name(self.pathValue)
return element[index]
if self.pathType == 'NAME':
element = self.driver.find_element_by_name(self.pathValue)
return element[index]
except NoSuchElementException:
return None
def get_element_list(self):
"""
get element list
:return: element list
"""
try:
if self.pathType == 'ID':
element_list = self.driver.find_element_by_id(self.pathValue)
return element_list
if self.pathType == 'XPATH':
element_list = self.driver.find_elements_by_xpath(self.pathValue)
return element_list
if self.pathType == 'CLASSNAME':
element_list = self.driver.find_element_by_class_name(self.pathValue)
return element_list
if self.pathType == 'NAME':
element_list = self.driver.find_element_by_name(self.pathValue)
return element_list
except NoSuchElementException:
return None
def click(self):
"""
click element
:return:
"""
element = self.get_element()
time.sleep(1)
element.click()
def send_key(self, key):
"""
input key
:param key: input value
:return:
"""
element = self.get_element()
time.sleep(1)
element.clear()
element.send_keys(key)
def input_keys(self, index, key):
"""
By index send key
:param index: index
:param key: key
:return:
"""
element = self.get_element_by_index(index)
time.sleep(1)
element.clear()
element.send_keys(key)
def get_text_value(self):
"""
get attribute
:return:
"""
element = self.get_element()
value = element.get_attribute('text')
return str(value)
```
**那些让人费神的测试数据文件:**
每一个好的测试,都离不开一份好的测试用例数据,那么,这么多的数据,我们要怎样进行管理才能既不乱又方便以后对数据进行更改维护呢?
其实,小编也不知道有什么好办法,小编就是使用excel文件来对测试用例进行统一管理的。请看下面:
![]()
形式就是这么个形式,内容就随便你们怎么修改了。毕竟我也只能帮你们到这里了。至于对excel文件内容的读取,在接口测试那篇博文中也有详细介绍哦。不明白的同学请移步:[]()
其实,出来测试用例,还有一个数量庞大的数据群体,就是:元素定位的数据,包括:id,name,classname,xpath等等,这些数据可是我们在测试过程中找到页面元素的不二法门。所以各位朋友一定要注意啦,一定要处理好它们。
请看下面:
![](https://img.kancloud.cn/71/c4/71c4ee6f25cae034b4f5beaa5fadea83_1033x516.png)