使用python+Selenium+unittest搭建一套web自动化测试项目

最近随着项目越来越大,页面也越来越多。这种regression的bug也屡见不鲜,造成这一原因的根本原因是,我们缺少了自动化测试。很多以前正常的功能,在无意间被破坏,而测试也只focus在新开发的功能上。这就造成,每当濒临发布,一堆的bug铺面而来。为了减少不必要的工作,一套自动化测试是非常有必要的。

此次,我会采用python+Selenium+unittest构建一套基本的自动化测试。

环境需求(window)

python3

ChromeDriver

项目搭建

项目结构

一、test_config(配置)

包含一系列系统运行所需的配置信息,包括地址信息,账号密码等

# -*- coding: utf-8 -*-

import os

test_home_url = 'http://baidu.com'

test_login_user_account = 'xxxxx'

test_login_user_password = 'xxxxx'

test_base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

test_log_path = test_base_path + os.path.sep + 'test_report' + os.path.sep + 'log' + os.path.sep

test_screenshot_path = test_base_path + os.path.sep + 'test_report' + os.path.sep + 'screenshot' + os.path.sep

test_report_path = test_base_path + os.path.sep + 'test_report' + os.path.sep + 'report' + os.path.sep

test_report_html_title = 'baidu_test_result'

test_data_path = test_base_path + os.path.sep + 'test_data' + os.path.sep

test_case_path = test_base_path + os.path.sep + 'test_suite' + os.path.sep + 'test_case' + os.path.sep

二、test_driver(驱动)

主要是做以下三个部分,检查浏览器驱动,及封装驱动使用

1). 可以根据浏览器类型选择驱动

# -*- coding: utf-8 -*-

from selenium import webdriver
from test_driver.chromeDriver import ChromeDriver

class BrowserDriver(object):
    def get_driver(self, browser="chrome"):
        if browser == "firefox" or browser == "ff":
            driver = webdriver.Firefox()
        elif browser == "internet explorer" or browser == "ie":
            driver = webdriver.Ie()
        elif browser == "opera":
            driver = webdriver.Opera()
        elif browser == "phantomjs":
            driver = webdriver.PhantomJS()
        elif browser == 'edge':
            driver = webdriver.Edge()
        else:
            chromedriver = ChromeDriver()
            chromedriver.check_update_chromedriver()
            driver = webdriver.Chrome()
        try:
            driver.maximize_window()
            driver.implicitly_wait(20)
            return driver
        except Exception:
            raise NameError(
                "Not found %s browser,You can enter 'ie', 'ff', 'opera', 'phantomjs', 'edge' or 'chrome'." % browser)

2). 检查所选浏览器类型,检查相应的浏览器版本和驱动版本是否一致

比如你选谷歌浏览器,则部分检查代码如下,需要根据浏览器版本下载相应的驱动到python的安装目录。

def check_update_chromedriver(self):
    '''
    Check chromedriver version and chrome browser version, if not compatible, download and update chromedriver version.
    '''
    warnings.simplefilter("ignore", ResourceWarning)
    chrome_version = self.get_chrome_version()
    chrome_main_version = int(chrome_version.split(".")[0])  # chrome main version

    driver_version = self.get_chrome_driver_version()
    driver_main_version = int(driver_version.split(".")[0])  # chromedriver main version

    if chrome_main_version == driver_main_version:
        print('Chromedriver version({}) is compatible with chrome browser({}), no need to update chromedriver version!'.format(driver_version,chrome_version))
    else:
        try:
            print("chromedriver version({}) is not compatible with chrome browser version({}), updating...Please wait...>>>".format(driver_version,chrome_version))
            self.get_latest_chrome_driver(chrome_version)
        except Exception as e:
            print(f'Fail to update: {e}')

3). 封装selenium的基本操作

包括最大化,点击,鼠标右键,元素查找等

class DriverProvider:
    def __init__(self, driver=None):
        if driver:
            self.driver = driver
        else:
            self.driver = BrowserDriver().get_driver()

    def close(self):
        self.driver.close()

    def quit(self):
        self.driver.quit()
    
    def get_element_attribute(self, loc, attr)
        try:
          e = self.driver.find_element(*loc)
          return e.get_attribute(attr)
        except:
          # print log
          # save snapshot screen
          pass

    def get_element_text(self, loc)
        pass

三、test_suite(测试用例)

包括一个你所需做的test_page, test_case, 和test_data, 此处我们的test_case可以使用unittest框架,也可以选择pytest。此处我们选择unittest进行架构,比如我们测试百度的首页及搜索功能。基本架子如下,当然你也可以根据自己的习惯去构建,我是将整个test suite又分拆成三个包:

1)case子包

提供对应页面的case,比如我这里做了首页的标题测试和搜索功能测试,当然可以更细节

class TestHomePage(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
      cls.page = HomePage()
      cls.page.open(test_home_url)

    def test_baidu_btn_title(self):
      self.assertEqual(self.page.get_baidu_button_text(), baidu_title)

    def test_baidu_search_function(self):
      self.page.fill_search_text(baidu_search_text)
      self.page.click_search_button()
      self.assertTrue(self.page.is_search_text_existed_in_first_list_item(baidu_search_text))

    def tearDown(self):
      self.page.driver.refresh()
      time.sleep(10)

    @classmethod
    def tearDownClass(cls):
      cls.page.quit()


if __name__ == '__main__':
    unittest.main()

2)page子包

提供对应页面的基于我们provider的操作,HomePage继承自DriverProvider(我们自己定义),最好是把我们的选择器也提取出来单独放在一个文件里,因为我们可以可以会经常修改选择器(随着前端开发的进行)。

from test_driver.driverProvider import DriverProvider as Provider
from selenium.webdriver.common.by import By
import time

class HomePage(Provider):
    # Check homepage - title
    def get_baidu_button_text(self):
        return self.get_element_attribute((By.XPATH, '//input[@id="su"]'), 'value', 'baidu_button_text')

    # fill search text
    def fill_search_text(self, kw):
      self.input_text((By.XPATH, '//input[@id="kw"]'), kw)
      time.sleep(2)

    # click search button
    def click_search_button(self):
      self.click_element((By.XPATH, '//input[@id="su"]'))
      time.sleep(5)

    # is search item existed
    def is_search_text_existed_in_first_list_item(self, text):
      searchText = self.get_element_text((By.XPATH, '//div[@class="content_left"]/div[1]/div/div/h3/a'))
      return text in searchText

3)data子包

提供我们测试时用到的数据,比如上面case用到的baidu_title,baidu_search_text

baidu_title = '百度一下'
baidu_search_text = '你好'

四、test_report(打印log和html报告)

log子目录存放我们跑测试过程中的日志。

report子目录存放我们html报告。

screenshot子目录存放case错误的页面截图。

此处我们使用的HtmlTestRunner进行报告的打印。可自行上网搜索报告模板,当然也可以使用jinjia2进行结果的打印。

上面搭建完成,基本就已经可以了,然后我们在startup里启动我们的自动化测试。

我们使用TestLoader去扫描case路径下的所有文件,然后使用HtmlTestRunner进行html报告的打印

import unittest
from test_config.config import test_case_path
from test_report.report import Report

if __name__ == '__main__':
    suite = unittest.TestSuite()
    loader = unittest.TestLoader()
    suite.addTests(loader.discover(test_case_path))
    Report(suite).run()

报告如下:

相关标签:
  • python
  • selenium
  • unittest
0人点赞

发表评论

当前游客模式,请登陆发言

所有评论(0)