webUI自动化测试框架

一、设计思路

框架采用python3+yaml+po+unittest+HTMLTestRunner等技术编写的UI自动化测试框架
1.使用Page Object模式将页面定位和业务操作分开,分离测试对象(元素对象)和测试脚本(用例脚本),一个页面建一个对象类,提高用例的可维护性;
2.使用yaml管理页面空间元素和测试用例数据。例如一个页面元素发生变化时,不需要去修改代码,只需要在对应的页面元素yaml文件中修改即可。
3.以每个页面作为模块管理,随时组装,互不影响。

二、测试框架分层

 

 

1.框架层:基础组件封装,支撑整个框架的流程执行及功能扩展
2.用例层:根据用例场景构造test测试方法
3.业务层:封装页面对象类,一个页面建立一个类,业务层基础基础层page类
4.基础层:二次开发selenium的元素定位已经操作
 

三、编写用例方法

例如我需要新增百度搜索测试场景用例:

1.在testyaml目录下新增一个页面对象yaml文件,利用封装的yamlload方法将yaml文件中的dom元素读取出来,提供给封装页面对象类调用并定元素操作。

testinfo:
      - id: test_login001
        title: 登录百度网页测试
        info: 打开百度首页
testcase:
      - element_info: s-usersetting-top
        find_type: ID
        operate_type: click
        info: 打开登录对话框
      - element_info: userName
        find_type: ID
        operate_type: send_keys
        info: 输入用户名称
      - element_info: TANGRAM__PSP_11__password
        find_type: ID
        operate_type: send_keys
        info: 输入密码
      - element_info: TANGRAM__PSP_11__submit
        find_type: ID
        operate_type: click
        info: 单击登录按钮

check:
      - element_info: //*[@id="user"]/span[2]
        find_type: XPATH
        info: 检查用户是否登录

  

2.在testdata目录下新增一个yaml文件提供给用例测试数据

-
  id: test_login001.1
  detail : 验证登录成功
  screenshot : phone_pawd_empty
  data:
    username: 13501198450
    password: Han520520
  check :
     - hhil833

3.在page_obj目录编写百度搜索场景的页面对象类封装

testData = getyaml(setting.TEST_Element_YAML + '/' + 'baidu_login.yaml')
class baidu_login(Page):

    def  open_login(self,username,pwd):
        """

              :return:
              """
        dig_login_button_loc = (By.ID, testData.get_elementinfo(0))
        self.find_element(*dig_login_button_loc).click()
        sleep(1)
    def go_login(self,username,pwd):
        self.find_element(By.ID, testData.get_elementinfo(1)).send_keys(username)
        sleep(1)
        self.find_element(By.ID, testData.get_elementinfo(2)).send_keys(pwd)
        sleep(1)
        self.find_element(By.ID, testData.get_elementinfo(3)).click()

    def user_login(self, username, pwd):
        self.go_login(username,pwd)
        sleep(1)
        check = (By.ID, By.ID,testData.get_CheckElementinfo(0))
        return  self.find_element(*check).text

4.在testcase目录编写测试用例文件,采用ddt数据驱动读取yaml测试数据源文件

    @ddt.data(*testData)
    def user_login_verify(self, username, password):
        """
               用户登录
               :param phone: 手机号
               :param password: 密码
               :return:

               """

        baidu_login(self.driver).user_login(username,password)
    def test_login(self,datayaml):
        """
                登录测试
                :param datayaml: 加载login_data登录测试数据
                :return:
                """
        self.log.info("当前执行测试用例ID-> {0} ; 测试点-> {1}".format(datayaml['id'],datayaml['detail']))
        # c = self.user_login_verify(datayaml["username"],datayaml["password"])
        # log.info("检查点-> {0}".format(c))
        # self.assertEqual(c, datayaml['check'][0],
        #                  "成功登录,返回实际结果是->: {0}".format(c))

5.通过多线程将驱动传给执行方法,并行开启多个浏览器执行测试

    def run_case(self,function,name):
        thread_list=[]
        for i in range(1):
            appium_server = threading.Thread(target=function,args=(name,))
            thread_list.append(appium_server)
            for j in thread_list:
                j.start()

    def run_casea(self):
        name = ["chrome", "chrome"]
        for i in name:
            self.run_case(self.test_baidu,i)

  

6.操作元素封装

def get_element(self, find_type, element=""):
    # getdata = getyaml(file)

    # type = getdata.get_find_type(find_type_index)
    if find_type == "id" or find_type == "ID":
        print(1111111111111111111111)
        return self.driver.find_element_by_id(element)
    elif find_type == "xpath" or find_type == "XPATH":
        return self.driver.find_element_by_xpath(element)
    elif find_type == "name" or find_type == "NAME":
        return self.driver.find_element_by_name(element)
    else:
        raise Exception("错误!")

7.浏览器驱动封装

 
from typing import Union, Type
from selenium.webdriver import *
from selenium.webdriver.opera.options import Options as OperaOptions
from selenium.webdriver.edge.options import Options as EdgeOptions
from setting import *

BROWSERS = (Chrome, Ie, Firefox, Edge, Opera, PhantomJS)
OPTIONS = (ChromeOptions, IeOptions, FirefoxOptions, EdgeOptions, OperaOptions)


class BROWSER:

CHROME_DRIVER_PATH = CHROME_DRIVER_PATH

# 使用32位ie驱动解决文本输入缓慢的问题
IE_DRIVER_PATH = IE_DRIVER_PATH

FIREFOX_DRIVER_PATH = FIREFOX_DRIVER_PATH
EDGE_DRIVER_PATH = EDGE_DRIVER_PATH
OPERA_DRIVER_PATH = OPERA_DRIVER_PATH

HEADLESS = HEADLESS

# IMPLICITLY WAITING TIME METHOD
IMPLICITLY_WAIT_TIME = 10

# PAGE SOURCE LOAD TIME METHOD
PAGE_LOAD_TIME = 10

# the script should wait during an
# execute_async_script call before throwing an error
SCRIPT_TIMEOUT = 0

# SET WINDOW SIZE METHOD
WINDOWS_SIZE = (1024, 900)

def __init__(self, browser_type: Type[Union[Chrome, Ie, Firefox, Edge, Opera, PhantomJS, Remote]] = Chrome,
option_type: Type[Union[FirefoxOptions, ChromeOptions, IeOptions, EdgeOptions, OperaOptions]] = ChromeOptions,
driver_path: str = CHROME_DRIVER_PATH):
if not issubclass(browser_type, BROWSERS):
raise TypeError
if not issubclass(option_type, OPTIONS):
raise TypeError
if not isinstance(driver_path, str):
raise TypeError
self._driver = browser_type
self._option = option_type
self._path = driver_path

@property
def browser(self):
"""
subclass should implement this method
return the instance of WebDriver
:return:
"""
return

@property
def _options(self):
"""
subclass should implement this method
return instance of the Option Type like ChromeOptions
:return:
"""
return


class CHROME(BROWSER):

METHOD_MARK = True

IMPLICITLY_WAIT_TIME = 30

PAGE_LOAD_TIME = 20

SCRIPT_TIMEOUT = 10

# HEADLESS MODEL OPTION
HEADLESS = False

OPTION_MARK = True

# EXPERIMENTAL OPTION
EXPERIMENTAL = {
# 'mobileEmulation': {'deviceName': 'iPhone 6'}, #以移动格式现实启动页面做h5时候会用到
'excludeSwitches': ['enable-automation'] #浏览器启动时左上角提示正在运行自动化
}

# WINDOW SIZE OPTION
WINDOW_SIZE = ''
# WINDOW_SIZE = '--window-size=1920,1080'

# START MAXIMIZED OPTION
START_MAXIMIZED = '--start-maximized'

@property
def _options(self):
"""
chrome浏览器特有的操作属性
:return:
"""
if self.OPTION_MARK:
chrome_option = self._option()
chrome_option.headless = self.HEADLESS
if self.WINDOW_SIZE:
chrome_option.add_argument(self.WINDOW_SIZE)
if self.START_MAXIMIZED:
# chrome_option.add_argument(self.START_MAXIMIZED)
chrome_option.add_argument('--headless')
chrome_option.add_argument('--disable-gpu')

for k, v in self.EXPERIMENTAL.items():
chrome_option.add_experimental_option(k, v)
return chrome_option
return None

@property
def browser(self):
"""
启动chrome浏览器并进行初始配置
:return:
"""

if self._options:
chrome = self._driver(self._path, options=self._options)
else:
chrome = self._driver(self._path)

if self.METHOD_MARK:
chrome.implicitly_wait(self.IMPLICITLY_WAIT_TIME)
chrome.set_page_load_timeout(self.PAGE_LOAD_TIME)
chrome.set_script_timeout(self.SCRIPT_TIMEOUT)
return chrome



class IE(BROWSER):

IMPLICITLY_WAIT_TIME = 20

PAGE_LOAD_TIME = 10

SCRIPT_TIMEOUT = 10

WINDOWS_SIZE = (1600, 1024)

CLEAN_SESSION = True

ATTACH_TIMEOUT = 10000

MARK = True

def __init__(self):
super(IE, self).__init__(
browser_type=Ie,
option_type=IeOptions,
driver_path=super().IE_DRIVER_PATH
)

@property
def _options(self):
"""
ie浏览器特有的操作属性
:return:
"""
ie_option = self._option()
ie_option.browser_attach_timeout = self.ATTACH_TIMEOUT
ie_option.ensure_clean_session = self.CLEAN_SESSION
return ie_option

@property
def browser(self):
"""
启动ie浏览器并进行初始配置
:return:
"""
if self.MARK:
ie = self._driver(self._path, options=self._options)
else:
ie = self._driver(self._path)
ie.implicitly_wait(self.IMPLICITLY_WAIT_TIME)
ie.set_page_load_timeout(self.PAGE_LOAD_TIME)
ie.set_script_timeout(self.SCRIPT_TIMEOUT)
ie.set_window_size(*self.WINDOWS_SIZE)
return ie


class FIREFOX(BROWSER):

def __init__(self):
super(FIREFOX, self).__init__(
browser_type=Firefox,
option_type=FirefoxOptions,
driver_path=super().FIREFOX_DRIVER_PATH
)

@property
def _options(self):
return

def browser(self):
return self._driver(self._path)


class OPERA(BROWSER):

def __init__(self):
super(OPERA, self).__init__(
browser_type=Opera,
option_type=OperaOptions,
driver_path=super().OPERA_DRIVER_PATH
)

@property
def _options(self):
return

def browser(self):
return self._driver(self._path)

  

 

  

 
posted @ 2022-10-25 21:34  hanjialong  阅读(968)  评论(0编辑  收藏  举报