• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

拥抱自动化测试,极快升职加薪丄Selenium+Pytest自动化测试框架做到

武飞扬头像
锦都不二
帮助1

目录:导读

引言

Selenium Pytest自动化测试框架是目前最流行的自动化测试工具之一,其强大的功能和易用性援助许多开发人员和测试人员。

selenium自动化 pytest测试框架禅道实战

选用的测试网址为我电脑本地搭建的禅道

conftest.py更改

config.ini更改

conf.py更改

page更改

page_element更改

page_object更改

TestCase更改

测试结果

写在最后


引言

Selenium Pytest自动化测试框架是目前最流行的自动化测试工具之一,其强大的功能和易用性援助许多开发人员和测试人员。

当前最新消息显示,随着人们对软件质量的要求不断提高,自动化测试工作正在变得越来越重要。这也导致越来越多的公司和组织开始招聘具有自动化测试技能的人才,并愿意为其提供更高的薪酬和晋升机会。

在这种情况下,学习并掌握Selenium Pytest自动化测试框架将成为一个非常有价值的能力,并且有望帮助你在职场上实现快速升职加薪的目标。

因此,如果你想迅速提高自己的技能并进一步发展职业生涯,请跟随我们的指引,学习Selenium Pytest自动化测试框架,并使用它来实现高效的自动化测试工作!

前段时间有人问我登录携带登录的测试框架该怎么处理,今天就对框架做一点小升级吧,加入登录的测试功能。

selenium自动化 pytest测试框架禅道实战

选用的测试网址为我电脑本地搭建的禅道

更改了以下的一些文件,框架为原文章框架主体

conftest.py更改

conftest.py

  1.  
    #!/usr/bin/env python3
  2.  
    # -*- coding:utf-8 -*-
  3.  
    import base64
  4.  
    import pytest
  5.  
    import allure
  6.  
    from py.xml import html
  7.  
    from selenium import webdriver
  8.  
    from page.webpage import WebPage
  9.  
    from common.readconfig import ini
  10.  
    from tools.send_mail import send_report
  11.  
    from tools.times import timestamp
  12.  
    from config.conf import cm
  13.  
     
  14.  
    driver = None
  15.  
     
  16.  
     
  17.  
    @pytest.fixture(scope='session', autouse=True)
  18.  
    def drivers(request):
  19.  
    global driver
  20.  
    if driver is None:
  21.  
    driver = webdriver.Chrome()
  22.  
    web = WebPage(driver)
  23.  
    web.get_url(ini.url)
  24.  
     
  25.  
    def fn():
  26.  
    driver.quit()
  27.  
     
  28.  
    request.addfinalizer(fn)
  29.  
    return driver
  30.  
     
  31.  
     
  32.  
    @pytest.hookimpl(hookwrapper=True)
  33.  
    def pytest_runtest_makereport(item):
  34.  
    """
  35.  
    当测试失败的时候,自动截图,展示到html报告中
  36.  
    :param item:
  37.  
    """
  38.  
    pytest_html = item.config.pluginmanager.getplugin('html')
  39.  
    outcome = yield
  40.  
    report = outcome.get_result()
  41.  
    extra = getattr(report, 'extra', [])
  42.  
     
  43.  
    if report.when == 'call' or report.when == "setup":
  44.  
    xfail = hasattr(report, 'wasxfail')
  45.  
    if (report.skipped and xfail) or (report.failed and not xfail):
  46.  
    screen_img = _capture_screenshot()
  47.  
    if screen_img:
  48.  
    html = '<div><img src="data:image/png;base64,%s" alt="screenshot" style="width:1024px;height:768px;" ' \
  49.  
    'onclick="window.open(this.src)" align="right"/></div>' % screen_img
  50.  
    extra.append(pytest_html.extras.html(html))
  51.  
    report.extra = extra
  52.  
    report.description = str(item.function.__doc__)
  53.  
     
  54.  
     
  55.  
    def pytest_html_results_table_header(cells):
  56.  
    cells.insert(1, html.th('用例名称'))
  57.  
    cells.insert(2, html.th('Test_nodeid'))
  58.  
    cells.pop(2)
  59.  
     
  60.  
     
  61.  
    def pytest_html_results_table_row(report, cells):
  62.  
    cells.insert(1, html.td(report.description))
  63.  
    cells.insert(2, html.td(report.nodeid))
  64.  
    cells.pop(2)
  65.  
     
  66.  
     
  67.  
    def pytest_html_results_table_html(report, data):
  68.  
    if report.passed:
  69.  
    del data[:]
  70.  
    data.append(html.div('通过的用例未捕获日志输出.', class_='empty log'))
  71.  
     
  72.  
     
  73.  
    def pytest_html_report_title(report):
  74.  
    report.title = "pytest示例项目测试报告"
  75.  
     
  76.  
     
  77.  
    def pytest_configure(config):
  78.  
    config._metadata.clear()
  79.  
    config._metadata['测试项目'] = "测试百度官网搜索"
  80.  
    config._metadata['测试地址'] = ini.url
  81.  
     
  82.  
     
  83.  
    def pytest_html_results_summary(prefix, summary, postfix):
  84.  
    # prefix.clear() # 清空summary中的内容
  85.  
    prefix.extend([html.p("所属部门: XX公司测试部")])
  86.  
    prefix.extend([html.p("测试执行人: 随风挥手")])
  87.  
     
  88.  
     
  89.  
    def pytest_terminal_summary(terminalreporter, exitstatus, config):
  90.  
    """收集测试结果"""
  91.  
    result = {
  92.  
    "total": terminalreporter._numcollected,
  93.  
    'passed': len(terminalreporter.stats.get('passed', [])),
  94.  
    'failed': len(terminalreporter.stats.get('failed', [])),
  95.  
    'error': len(terminalreporter.stats.get('error', [])),
  96.  
    'skipped': len(terminalreporter.stats.get('skipped', [])),
  97.  
    # terminalreporter._sessionstarttime 会话开始时间
  98.  
    'total times': timestamp() - terminalreporter._sessionstarttime
  99.  
    }
  100.  
    print(result)
  101.  
    if result['failed'] or result['error']:
  102.  
    send_report()
  103.  
     
  104.  
     
  105.  
    def _capture_screenshot():
  106.  
    """截图保存为base64"""
  107.  
    now_time, screen_path = cm.screen_file
  108.  
    driver.save_screenshot(screen_path)
  109.  
    allure.attach.file(screen_path, "测试失败截图...{}".format(
  110.  
    now_time), allure.attachment_type.PNG)
  111.  
    with open(screen_path, 'rb') as f:
  112.  
    imagebase64 = base64.b64encode(f.read())
  113.  
    return imagebase64.decode()
  114.  
     
学新通

config.ini更改

  1.  
    [HOST]
  2.  
    HOST = http://127.0.0.1/zentao/user-login-L3plbnRhby9teS5odG1s.html

conf.py更改

  1.  
    #!/usr/bin/env python3
  2.  
    # -*- coding:utf-8 -*-
  3.  
    import os
  4.  
    from selenium.webdriver.common.by import By
  5.  
    from tools.times import datetime_strftime
  6.  
     
  7.  
     
  8.  
    class ConfigManager(object):
  9.  
    # 项目目录
  10.  
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  11.  
     
  12.  
    # 日志目录
  13.  
    LOG_PATH = os.path.join(BASE_DIR, 'logs')
  14.  
     
  15.  
    # 报告目录
  16.  
    REPORT_PATH = os.path.join(BASE_DIR, 'report', 'report.html')
  17.  
     
  18.  
    ELEMENT_PATH = os.path.join(BASE_DIR, 'page_element')
  19.  
     
  20.  
    # 元素定位的类型
  21.  
    LOCATE_MODE = {
  22.  
    'css': By.CSS_SELECTOR,
  23.  
    'xpath': By.XPATH,
  24.  
    'name': By.NAME,
  25.  
    'id': By.ID,
  26.  
    'class': By.CLASS_NAME
  27.  
    }
  28.  
     
  29.  
    # 邮件信息
  30.  
    EMAIL_INFO = {
  31.  
    'username': '1084502012@qq.com', # 切换成你自己的地址
  32.  
    'password': 'QQ邮箱授权码',
  33.  
    'smtp_host': 'smtp.qq.com',
  34.  
    'smtp_port': 465
  35.  
    }
  36.  
     
  37.  
    # 收件人
  38.  
    ADDRESSEE = [
  39.  
    '1084502012@qq.com',
  40.  
    ]
  41.  
     
  42.  
    @property
  43.  
    def ini_file(self):
  44.  
    # 配置文件
  45.  
    _file = os.path.join(self.BASE_DIR, 'config', 'config.ini')
  46.  
    if not os.path.exists(_file):
  47.  
    raise FileNotFoundError("配置文件%s不存在!" % _file)
  48.  
    return _file
  49.  
     
  50.  
    def element_file(self, name):
  51.  
    """页面元素文件"""
  52.  
    element_path = os.path.join(self.ELEMENT_PATH, '%s.yaml' % name)
  53.  
    if not os.path.exists(element_path):
  54.  
    raise FileNotFoundError("%s 文件不存在!" % element_path)
  55.  
    return element_path
  56.  
     
  57.  
    @property
  58.  
    def log_path(self):
  59.  
    log_path = os.path.join(self.BASE_DIR, 'logs')
  60.  
    if not os.path.exists(log_path):
  61.  
    os.makedirs(log_path)
  62.  
    return os.path.join(log_path, "%s.log" % datetime_strftime())
  63.  
     
  64.  
    @property
  65.  
    def screen_file(self):
  66.  
    now_time = datetime_strftime("%Y%m%d%H%M%S")
  67.  
    # 截图目录
  68.  
    screenshot_dir = os.path.join(self.BASE_DIR, 'screen_capture')
  69.  
    if not os.path.exists(screenshot_dir):
  70.  
    os.makedirs(screenshot_dir)
  71.  
    screen_path = os.path.join(screenshot_dir, "{}.png".format(now_time))
  72.  
    return now_time, screen_path
  73.  
     
  74.  
     
  75.  
    cm = ConfigManager()
  76.  
    if __name__ == '__main__':
  77.  
    print(cm.BASE_DIR)
  78.  
     
学新通

page更改

webpage.py

添加了几个函数!

  1.  
    #!/usr/bin/env python3
  2.  
    # -*- coding:utf-8 -*-
  3.  
    """
  4.  
    selenium基类
  5.  
    本文件存放了selenium基类的封装方法
  6.  
    """
  7.  
    from selenium.webdriver.support import expected_conditions as EC
  8.  
    from selenium.webdriver.support.ui import WebDriverWait
  9.  
    from selenium.common.exceptions import TimeoutException, NoSuchElementException
  10.  
    from config.conf import cm
  11.  
    from tools.times import sleep
  12.  
    from tools.logger import Logger
  13.  
     
  14.  
    log = Logger(__name__).logger
  15.  
     
  16.  
     
  17.  
    class WebPage(object):
  18.  
    """selenium基类"""
  19.  
     
  20.  
    def __init__(self, driver):
  21.  
    # self.driver = webdriver.Chrome()
  22.  
    self.driver = driver
  23.  
    self.timeout = 20
  24.  
    self.wait = WebDriverWait(self.driver, self.timeout)
  25.  
     
  26.  
    def get_url(self, url):
  27.  
    """打开网址并验证"""
  28.  
    self.driver.maximize_window()
  29.  
    self.driver.set_page_load_timeout(60)
  30.  
    try:
  31.  
    self.driver.get(url)
  32.  
    self.driver.implicitly_wait(10)
  33.  
    log.info("打开网页:%s" % url)
  34.  
    except TimeoutException:
  35.  
    raise TimeoutException("打开%s超时请检查网络或网址服务器" % url)
  36.  
     
  37.  
    @staticmethod
  38.  
    def element_locator(func, locator):
  39.  
    """元素定位器"""
  40.  
    name, value = locator
  41.  
    return func(cm.LOCATE_MODE[name], value)
  42.  
     
  43.  
    def find_element(self, locator):
  44.  
    """寻找单个元素"""
  45.  
    return WebPage.element_locator(lambda *args: self.wait.until(
  46.  
    EC.presence_of_element_located(args)), locator)
  47.  
     
  48.  
    def find_elements(self, locator):
  49.  
    """查找多个相同的元素"""
  50.  
    return WebPage.element_locator(lambda *args: self.wait.until(
  51.  
    EC.presence_of_all_elements_located(args)), locator)
  52.  
     
  53.  
    def focus(self):
  54.  
    """聚焦元素"""
  55.  
    self.driver.execute_script("window.scrollTo(0,document.body.scrollHeight)")
  56.  
     
  57.  
    def elements_num(self, locator):
  58.  
    """获取相同元素的个数"""
  59.  
    number = len(self.find_elements(locator))
  60.  
    log.info("相同元素:{}".format((locator, number)))
  61.  
    return number
  62.  
     
  63.  
    def input_text(self, locator, txt):
  64.  
    """输入(输入前先清空)"""
  65.  
    sleep(0.5)
  66.  
    ele = self.find_element(locator)
  67.  
    ele.clear()
  68.  
    ele.send_keys(txt)
  69.  
    log.info("输入文本:{}".format(txt))
  70.  
     
  71.  
    def is_click(self, locator):
  72.  
    """点击"""
  73.  
    ele = self.find_element(locator)
  74.  
    ele.click()
  75.  
    sleep()
  76.  
    log.info("点击元素:{}".format(locator))
  77.  
     
  78.  
    def is_exists(self, locator):
  79.  
    """元素是否存在(DOM)"""
  80.  
    try:
  81.  
    WebPage.element_locator(lambda *args: EC.presence_of_element_located(args)(self.driver), locator)
  82.  
    return True
  83.  
    except NoSuchElementException:
  84.  
    return False
  85.  
     
  86.  
    def alert_exists(self):
  87.  
    """判断弹框是否出现,并返回弹框的文字"""
  88.  
    alert = EC.alert_is_present()(self.driver)
  89.  
    if alert:
  90.  
    text = alert.text
  91.  
    log.info("Alert弹窗提示为:%s" % text)
  92.  
    alert.accept()
  93.  
    return text
  94.  
    else:
  95.  
    log.error("没有Alert弹窗提示!")
  96.  
     
  97.  
    def element_text(self, locator):
  98.  
    """获取当前的text"""
  99.  
    _text = self.find_element(locator).text
  100.  
    log.info("获取文本:{}".format(_text))
  101.  
    return _text
  102.  
     
  103.  
    def get_attribute(self, locator, name):
  104.  
    """获取元素属性"""
  105.  
    return self.find_element(locator).get_attribute(name)
  106.  
     
  107.  
    @property
  108.  
    def get_source(self):
  109.  
    """获取页面源代码"""
  110.  
    return self.driver.page_source
  111.  
     
  112.  
    def refresh(self):
  113.  
    """刷新页面F5"""
  114.  
    self.driver.refresh()
  115.  
    self.driver.implicitly_wait(30)
  116.  
     
  117.  
     
  118.  
    if __name__ == "__main__":
  119.  
    pass
  120.  
     
学新通

page_element更改

login.yaml

  1.  
    账号: "css==input[name=account]"
  2.  
    密码: "css==input[name=password]"
  3.  
    登录: "css==button#submit"
  4.  
    我的地盘: "xpath==//nav[@id='navbar']//span[text()=' 我的地盘']"
  5.  
    右上角名称: "css==.user-name"
  6.  
    退出登录: "xpath==//a[text()='退出']"

product.yaml

  1.  
    产品按钮: "xpath==//nav[@id='navbar']//a[text()='产品']"
  2.  
    添加产品: "xpath==//div[@id='pageActions']//a[text()=' 添加产品']"
  3.  
    产品名称: "css==#name"
  4.  
    产品代号: "css==#code"
  5.  
    保存产品: "css==#submit"
  6.  
    产品列表: "xpath==//ul[@class='nav nav-stacked nav-secondary scrollbar-hover']//a[1]"
  7.  
     

page_object更改

loginpage.py

  1.  
    #!/usr/bin/env python3
  2.  
    # -*- coding: utf-8 -*-
  3.  
    from page.webpage import WebPage
  4.  
    from common.readelement import Element
  5.  
     
  6.  
    login = Element('login')
  7.  
     
  8.  
     
  9.  
    class LoginPage(WebPage):
  10.  
    """登录类"""
  11.  
     
  12.  
    def username(self, name):
  13.  
    """用户名"""
  14.  
    self.input_text(login['账号'], name)
  15.  
     
  16.  
    def password(self, pwd):
  17.  
    """密码"""
  18.  
    self.input_text(login['密码'], pwd)
  19.  
     
  20.  
    def submit(self):
  21.  
    """登录"""
  22.  
    self.is_click(login['登录'])
  23.  
     
  24.  
    def quit_login(self):
  25.  
    """退出登录"""
  26.  
    self.is_click(login['右上角名称'])
  27.  
    self.is_click(login['退出登录'])
  28.  
     
  29.  
    def login_success(self):
  30.  
    """验证登录"""
  31.  
    return self.is_exists(login['我的地盘'])
学新通

productpage.py

  1.  
    #!/usr/bin/env python3
  2.  
    # -*- coding:utf-8 -*-
  3.  
    from page.webpage import WebPage, sleep
  4.  
    from common.readelement import Element
  5.  
     
  6.  
    product = Element('product')
  7.  
     
  8.  
     
  9.  
    class ProductPage(WebPage):
  10.  
    """产品类"""
  11.  
     
  12.  
    def click_product(self):
  13.  
    """点击产品"""
  14.  
    self.is_click(product['产品按钮'])
  15.  
     
  16.  
    def add_product(self):
  17.  
    """添加产品"""
  18.  
    self.is_click(product['添加产品'])
  19.  
     
  20.  
    def add_product_content(self, name, code):
  21.  
    """添加产品内容"""
  22.  
    self.input_text(product['产品名称'], name)
  23.  
    self.input_text(product['产品代号'], code)
  24.  
     
  25.  
    def save_product(self):
  26.  
    """保存产品"""
  27.  
    self.focus()
  28.  
    self.is_click(product['保存产品'])
  29.  
     
  30.  
    def product_list(self):
  31.  
    """产品列表"""
  32.  
    return [i.get_attribute('title') for i in self.find_elements(product['产品列表'])]
  33.  
     
  34.  
     
  35.  
    if __name__ == '__main__':
  36.  
    a = product['产品列表'][1] "[1]"
  37.  
    print(a)
  38.  
     
学新通

TestCase更改

test_login.py

  1.  
    #!/usr/bin/env python3
  2.  
    # -*- coding: utf-8 -*-
  3.  
    import pytest
  4.  
    from tools.times import sleep
  5.  
    from page_object.loginpage import LoginPage
  6.  
     
  7.  
     
  8.  
    class TestLogin:
  9.  
    """测试登录"""
  10.  
     
  11.  
    @pytest.mark.parametrize("name,pwd", [('admin', 'Admin123456'), ('test', 'test123')])
  12.  
    def test_001(self, drivers, name, pwd):
  13.  
    login = LoginPage(drivers)
  14.  
    login.username(name)
  15.  
    login.password(pwd)
  16.  
    login.submit()
  17.  
    sleep(3)
  18.  
    res = login.alert_exists()
  19.  
    if res:
  20.  
    assert res == "登录失败,请检查您的用户名或密码是否填写正确。"
  21.  
    elif login.login_success():
  22.  
    login.quit_login()
  23.  
     
学新通

test_product.py

  1.  
    #!/usr/bin/env python3
  2.  
    # -*- coding:utf-8 -*-
  3.  
    import pytest
  4.  
    import allure
  5.  
    from random import randint
  6.  
    from tools.times import sleep
  7.  
    from page_object.loginpage import LoginPage
  8.  
    from page_object.productpage import ProductPage
  9.  
     
  10.  
     
  11.  
    @allure.feature("测试产品模块")
  12.  
    class TestProduct:
  13.  
     
  14.  
    @pytest.fixture(scope='class', autouse=True)
  15.  
    def is_login(self, request, drivers):
  16.  
    login = LoginPage(drivers)
  17.  
    login.username('admin')
  18.  
    login.password('Admin123456')
  19.  
    login.submit()
  20.  
    sleep(3)
  21.  
     
  22.  
    def logout():
  23.  
    login.quit_login()
  24.  
     
  25.  
    request.addfinalizer(logout)
  26.  
     
  27.  
    @allure.story("测试添加产品")
  28.  
    def test_001(self, drivers):
  29.  
    """搜索"""
  30.  
    product = ProductPage(drivers)
  31.  
    product.click_product()
  32.  
    product.add_product()
  33.  
    name, code = randint(100, 999), randint(100, 999)
  34.  
    product.add_product_content(name, code)
  35.  
    product.save_product()
  36.  
    sleep(3)
  37.  
    product.click_product()
  38.  
    assert str(name) in product.product_list()
  39.  
     
  40.  
     
  41.  
    if __name__ == '__main__':
  42.  
    pytest.main(['TestCase/test_aproduct.py'])
  43.  
     
学新通

测试结果

登录之后的测试用例:

学新通

测试登录的用例

学新通

写在最后

这篇贴子到这里就结束了,最后,希望看这篇帖子的朋友能够有所收获。

都到这了记得三连支持一下吧。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhggbhkg
系列文章
更多 icon
同类精品
更多 icon
继续加载