news 2026/6/10 17:17:35

Selenium Web自动化实践案例,跟着敲代码真香

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Selenium Web自动化实践案例,跟着敲代码真香

1项目背景

https://passport.csdn.net/login CSDN登录页面

2功能实现

·自动运行用例

·自动生成测试报告

·自动断言与截图

·自动将最新测试报告发送到指定邮箱

·数据,页面元素分离

·PageObject+Unittest+ddt数据驱动用例

·执行日志、分布式执行

3项目架构

4浏览器Driver定义

  1. from common.readFile import ReadFile

  2. from common.logger import Logger

  3. from selenium import webdriver

  4. logger = Logger()

  5. from selenium.webdriver import Remote

  6. class Browser():

  7. def __init__(self):

  8. config = ReadFile()

  9. self.browser = config.readConfig("Browser", "browser")

  10. self.host = config.readConfig("host","host")

  11. logger.info("You had select {} host {} browser.".format(self.host,self.browser))

  12. def driver(self):

  13. """

  14. 启动浏览器驱动

  15. :return: 返回浏览器驱动URL

  16. """

  17. try:

  18. # driver = webdriver.Chrome()

  19. driver = Remote(command_executor='http://' + self.host + '/wd/hub',

  20. desired_capabilities={ 'platform': 'ANY',

  21. 'browserName': self.browser,

  22. 'version': "",

  23. 'javascriptEnabled': True

  24. }

  25. )

  26. return driver

  27. except Exception as msg:

  28. print("驱动异常-> {0}".format(msg))

5用例运行前后的环境准备工作

  1. import unittest

  2. from common.driver import Browser

  3. class StartEnd(unittest.TestCase):

  4. def setUp(self):

  5. self.driver = Browser().driver()

  6. self.driver.implicitly_wait(10)

  7. self.driver.maximize_window()

  8. def tearDown(self):

  9. self.driver.quit()

6工具方法模块

主要封装一些公共的方法如:截图,查找最新报告。

  1. import time

  2. from selenium import webdriver

  3. import os,sys

  4. sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))

  5. from config import setting

  6. def inser_img(driver):

  7. # 指定截图存放的根目录路径

  8. screen_dir = setting.TEST_REPORT + '/imges/'

  9. rq = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))

  10. screen_name = screen_dir + rq + '.png'

  11. driver.get_screenshot_as_file(screen_name)

  12. print('screenshot:' + screen_name)

  13. #查找最新的测试报告

  14. def latest_report(report_dir):

  15. lists = os.listdir(report_dir)

  16. lists.sort(key=lambda fn: os.path.getatime(report_dir + '\\' + fn))

  17. file = os.path.join(report_dir, lists[-1])

  18. return file

  19. def latest_report_img(report_dir):

  20. lists = os.listdir(report_dir)

  21. lists.sort(key=lambda fn: os.path.getatime(report_dir + '\\' + fn))

  22. file = os.path.join(report_dir, lists[-1])

  23. return file

7Pageobject页面对象封装

基础页面类

  1. import time

  2. from selenium import webdriver

  3. from selenium.common.exceptions import NoSuchElementException

  4. from common.logger import Logger

  5. from common.readFile import ReadFile

  6. logger = Logger()

  7. class BasePage():

  8. "定义一个页面基类,让所有页面都继承这个类,封装一些常用的页面操作方法到这个类"

  9. def __init__(self, driver):

  10. self.driver = driver

  11. config = ReadFile()

  12. self.baseurl = config.readConfig("BaseUrl", "url")

  13. def open_url(self, url):

  14. self.driver.get(self.baseurl + url)

  15. # 退出浏览器

  16. def quit_browser(self):

  17. self.driver.quit()

  18. # 浏览器前进操作

  19. def forward(self):

  20. self.driver.forward()

  21. # 浏览器后退操作

  22. def back(self):

  23. self.driver.back()

  24. # 隐式等待

  25. def wait(self, seconds):

  26. self.driver.implicitly_wait(seconds)

  27. # 查找元素

  28. def find_element(self, selector):

  29. selector_by = selector['find_type']

  30. selector_value = selector['element_info']

  31. try:

  32. if selector_by == 'id':

  33. el = self.driver.find_element_by_id(selector_value)

  34. elif selector_by == "n" or selector_by == 'name':

  35. el = self.driver.find_element_by_name(selector_value)

  36. elif selector_by == 'cs' or selector_by == 'css_selector':

  37. el = self.driver.find_element_by_css_selector(selector_value)

  38. elif selector_by == 'cn' or selector_by == 'classname':

  39. el = self.driver.find_element_by_class_name(selector_value)

  40. elif selector_by == "lt" or selector_by == 'link_text':

  41. el = self.driver.find_element_by_link_text(selector_value)

  42. elif selector_by == "plt" or selector_by == 'partial_link_text':

  43. el = self.driver.find_element_by_partial_link_text(selector_value)

  44. elif selector_by == "tn" or selector_by == 'tag_name':

  45. el = self.driver.find_element_by_tag_name(selector_value)

  46. elif selector_by == "x" or selector_by == 'xpath':

  47. el = self.driver.find_element_by_xpath(selector_value)

  48. elif selector_by == "ss" or selector_by == 'selector_selector':

  49. el = self.driver.find_element_by_css_selector(selector_value)

  50. else:

  51. raise NameError("Please enter a valid type of targeting elements.")

  52. except NoSuchElementException :

  53. logger.error("{0}页面中未能找到{1}元素".format(self, selector_value))

  54. return el

  55. # 输入

  56. def input(self, selector, text):

  57. el = self.find_element(selector)

  58. try:

  59. el.clear()

  60. el.send_keys(text)

  61. logger.info("Had type \' %s \' in inputBox" % text)

  62. except NameError as e:

  63. logger.error("Failed to type in input box with %s" % e)

  64. # 点击

  65. def click(self, selector):

  66. el = self.find_element(selector)

  67. try:

  68. logger.info("The element \' %s \' was clicked." % el.text)

  69. el.click()

  70. except NameError as e:

  71. logger.error("Failed to click the element with %s" % e)

  72. @staticmethod

  73. def sleep(seconds):

  74. time.sleep(seconds)

  75. logger.info("Sleep for %d seconds" % seconds)

  76. def get_text(self,selector):

  77. el = self.find_element(selector)

  78. try:

  79. return el.text

  80. except NameError as e:

  81. logger.error("Failed to text the element with %s" % e)

  82. def switch_frame(self, selector):

  83. """

  84. 多表单嵌套切换

  85. :param loc: 传元素的属性值

  86. :return: 定位到的元素

  87. """

  88. try:

  89. el = self.find_element(selector)

  90. return self.driver.switch_to_frame(el)

  91. except NoSuchElementException as e:

  92. logger.error("查找iframe异常-> {0}".format(e))

  93. def switch_windows(self, selector):

  94. """

  95. 多窗口切换

  96. :param loc:

  97. :return:

  98. """

  99. try:

  100. el = self.find_element(selector)

  101. return self.driver.switch_to_window(el)

  102. except NoSuchElementException as e:

  103. logger.error("查找窗口句柄handle异常-> {0}".format(e))

  104. def switch_alert(self):

  105. """

  106. 警告框处理

  107. :return:

  108. """

  109. try:

  110. return self.driver.switch_to_alert()

  111. except NoSuchElementException as e:

  112. logger.error("查找alert弹出框异常-> {0}".format(e))

LoginPage.py —— CNDS登录页面

  1. from pageObject.basePage import *

  2. from selenium import webdriver

  3. from common.readFile import ReadFile

  4. from config import setting

  5. login_el = ReadFile().readYaml(setting.TEST_Element_YAML + '/' + 'login.yaml')

  6. data = ReadFile().readYaml(setting.TEST_DATA_YAML + '/' + 'login_data.yaml')

  7. class CndsPage(BasePage):

  8. '''登录页面'''

  9. url = '/login'

  10. # 定位器,通过元素属性定位元素对象

  11. #选择账号密码登录

  12. chanlelogin_loc = login_el['testcase'][0]

  13. # 账号输入框

  14. username_loc = login_el['testcase'][1]

  15. # 密码输入框

  16. pwd_loc = login_el['testcase'][2]

  17. # 单击登录

  18. login_accout_loc = login_el['testcase'][3]

  19. def accout_login(self,accout,passwd):

  20. self.open_url(self.url)

  21. self.click(self.chanlelogin_loc)

  22. self.input(self.username_loc,accout)

  23. self.input(self.pwd_loc,passwd)

  24. self.click(self.login_accout_loc)

  25. # 定位器,通过元素属性定位检查项元素对象

  26. user_login_success_loc = login_el['check'][0]

  27. accout_id_loc = login_el['check'][1]

  28. accout_pawd_error_loc = login_el['check'][2]

  29. # 账号或密码错误提示

  30. def accout_passwd_error(self):

  31. return self.get_text(self.accout_pawd_error_loc)

  32. # 登录成功,跳转到个人资料页,获取用户名

  33. def get_account(self):

  34. self.click(self.user_login_success_loc)

  35. time.sleep(2)

  36. def user_login_success(self):

  37. return self.find_element(self.accout_id_loc).text

8组织测试用例

·用户名密码正确点击登录

·用户名正确,密码错误点击登录

  1. import unittest

  2. from common import function,myUnit,readFile

  3. from pageObject.loginPage import CndsPage

  4. from time import sleep

  5. from common.logger import Logger

  6. from config import setting

  7. import ddt

  8. log = Logger()

  9. testData= readFile.ReadFile().readYaml(setting.TEST_DATA_YAML + '/' + 'login_data.yaml')

  10. @ddt.ddt

  11. class LoginTest(myUnit.StartEnd):

  12. # @unittest.skip('skip this case')

  13. """CNDS登录测试"""

  14. def user_login_verify(self,account,passwd):

  15. """

  16. 用户登录

  17. :param :account 账号

  18. :param passwd: 密码

  19. :return:

  20. """

  21. CndsPage(self.driver).accout_login(account,passwd)

  22. @ddt.data(*testData)

  23. def test_login_normal(self,datayaml):

  24. log.info("test_login1_normal is start run...")

  25. self.user_login_verify(datayaml['data']['accout'],datayaml['data']['passwd'])

  26. sleep(3)

  27. #断言与截屏

  28. po = CndsPage(self.driver)

  29. if datayaml['screenshot'] == 'login_success':

  30. po.get_account()

  31. function.inser_img(self.driver)

  32. self.assertEqual(po.user_login_success(), datayaml['check'][0], "登录成功,返回实际结果是->: {0}".format(po.user_login_success()))

  33. else:

  34. function.inser_img(self.driver)

  35. self.assertEqual(po.accout_passwd_error(), datayaml['check'][0],"登录失败,返回实际结果是->: {0}".format(po.accout_passwd_error()))

  36. print("test_login1_normal is test end!")

9执行测试用例

  1. import unittest

  2. from common.function import latest_report

  3. from common.sendMail import *

  4. from config import setting

  5. from thridLib.HTMLTestRunner import HTMLTestRunner

  6. import time

  7. import os,sys

  8. sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))

  9. report_dir = setting.TEST_REPORT + '/report/'

  10. def add_case(test_path=setting.TEST_DIR):

  11. discover = unittest.defaultTestLoader.discover(test_path, pattern="test*.py")

  12. return discover

  13. def run_case(all_case,result_path=report_dir):

  14. print("start run testcase...")

  15. now = time.strftime("%Y-%m-%d %H_%M_%S")

  16. report_name = result_path + '/' + now + 'result.html'

  17. print("start write report...")

  18. #HTMLTestRunner测试报告

  19. with open(report_name, 'wb') as f:

  20. runner = HTMLTestRunner(stream=f, title='测试报告', description='用例执行情况') # 定义测试报告

  21. runner.run(all_case) # 执行测试用例

  22. f.close()

  23. print("find latest report...")

  24. # 查找最新的测试报告

  25. report = latest_report(result_path)

  26. # 邮件发送报告

  27. print("send email report...")

  28. send_mail(report)

  29. print("test end!")

  30. if __name__ == '__main__':

  31. cases = add_case()

  32. run_case(cases)

感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 9:06:36

AI人脸隐私卫士能否用于法庭证据?司法合规性探讨

AI人脸隐私卫士能否用于法庭证据?司法合规性探讨 1. 引言:AI人脸隐私保护的技术演进与法律挑战 随着人工智能技术的普及,个人隐私保护已成为数字时代的核心议题。尤其是在公共影像数据广泛采集的背景下,如何在保障信息可用性的同…

作者头像 李华
网站建设 2026/6/10 9:07:38

2026最新版《英雄无敌3:死亡阴影下载安装与修改器使用详解》——Win10/Win11完美运行教程

前言 本篇教程为你带来 2026最新版《英雄无敌3:死亡阴影下载安装与修改器教程》,内容涵盖安全下载渠道、完整安装步骤、兼容设置、避坑指南与修改器使用技巧。本文将从系统兼容性与游戏优化角度出发,手把手教你在 Windows10 / Windows11 环境…

作者头像 李华
网站建设 2026/6/10 8:58:58

AI手势识别模型内置于库中:零下载风险部署教程

AI手势识别模型内置于库中:零下载风险部署教程 1. 引言 1.1 手势识别的技术演进与应用前景 随着人机交互技术的不断进步,AI手势识别正逐步从实验室走向消费级产品。传统触控、语音控制之外,手势作为一种更自然、直观的交互方式&#xff0c…

作者头像 李华
网站建设 2026/6/10 9:06:35

HunyuanVideo-Foley移动端:Android/iOS集成音效生成SDK方案

HunyuanVideo-Foley移动端:Android/iOS集成音效生成SDK方案 随着短视频和移动内容创作的爆发式增长,音效作为提升视频沉浸感的关键要素,正受到越来越多开发者的关注。传统音效添加依赖人工剪辑与素材库匹配,效率低、成本高。为此…

作者头像 李华
网站建设 2026/6/10 10:46:46

MIPS与RISC-V架构下ALU定点运算完整指南

深入ALU核心:MIPS与RISC-V定点运算的设计哲学与实战精要 你有没有遇到过这样的情况——在写嵌入式C代码时,一个看似简单的加法操作 a b ,编译后却生成了多条汇编指令?或者你在调试时发现,某些算术运算的延迟远超预期…

作者头像 李华
网站建设 2026/6/10 10:40:06

OllyDbg调试Shellcode注入的全面讲解

深入实战:用 OllyDbg 精准捕获并分析 Shellcode 注入全过程你有没有遇到过这样的场景?一个看似普通的程序运行后突然弹出命令行、连接外网,或者悄悄释放文件,但你在IDA里翻遍了代码也没找到任何可疑调用。真相往往是——真正的恶意…

作者头像 李华