51Testing软件测试论坛

标题: Selenium自动化测试:8种元素定位+unittest框架设计 [打印本页]

作者: lsekfe    时间: 2021-9-18 11:23
标题: Selenium自动化测试:8种元素定位+unittest框架设计
作者简介
笔名,唐米。参与过汇丰银行,国家电网,中国电信等多个大型项目的研发和管理,擅长的技术领域为安全测试,性能测试,自动化框架搭建与维护,曾受南京航空航天大学邀请分享Linux、oracle等测试技术,具备10年开发+测试实战经验,担任过高级软件测试讲师,校企软件技术分享嘉宾。

1、摘要
主要技术点:
1、在项目网页中,以【html分析+selenium定位+python代码+运行结果页面】的模式详解8种元素的定位方法。
2、可以直接套用于项目的自动化框架:以开源项目Agileone为例,讲解一个项目的自动化测试框架如何设计与实现。

2、关键字
   Selenium自动化测试、Selenium+unittest+HTMLtestrunner框架设计、Selenium8种元素定位方法。

Selenium初识1.Selenium 简介
selenium 是一个 web 的自动化测试工具,通过使用浏览器访问目标站点进而对一个页面上的各个控件进行操作,如对输入框输入内容,对按钮点击,对页面刷新,对单选框,复选框进行点击选择等操作很好的实现了用工具模拟人的操作对访问进行自动化测试。在软件测试中可以很好的完成自动化测试,在爬虫中使用,selenium通过驱动浏览器,完全模拟浏览的操作,比如跳转、输入、点击、下拉等进而进行跳转,获取页面有用信息。

2.Selenium使用环境
这个要从selenium的使用环境说起,使用selenium的过程中会加载浏览器,比如chrome,则需要在本地加载与浏览器版本匹配的驱动文件。
一、介绍
Selenium作为python的独立的第三方库使用,需要通过pip命令安装,命令如:pip install selenium,核心为webdriver驱动,py文件中通过from selenium import webdriver导入,导入驱动后赋值给对象driver,通过driver的各种方法操作页面对象。
总结selenium使用环境:
1、python语言环境下
2、浏览器(如chrome)
3、浏览器对应的驱动文件(webdriverchrome.exe)
代码如下:
[attach]134470[/attach]
  1. #导入驱动文件
  2. from selenium import webdriver
  3. # 加载驱动文件的路径
  4. driver=webdriver.Chrome(r'C:\webdriver\chromedriver.exe')
复制代码
Selenium 8种方法定位元素
Web页面的控件可以通过元素定位的方式获取到,在当前web页面上,鼠标右击查看源码,调出html源代码。通过html中的标签及其属性结合selenium的元素定位方法可以定位到需要的输入框、按钮、链接、图片等页面元素。
[attach]134471[/attach]
①、通过id定位元素
agileone这个项目中,可以发现用户名的输入框,其中id的值为‘usernmae’,则可以通过find_element_by_id("username")获取到输入框。
[attach]134472[/attach]
可运行代码如下:
  1. from selenium import webdriver
  2. import time
  3. # 驱动文件路径
  4. driver=webdriver.Chrome(r"E:\webdriver\chromedriver.exe")#加载chromedriver驱动
  5. # 打开百度首页
  6. driver.get("http://localhost:8081/agileone/")
  7. # 等待网页打开
  8. time.sleep(5)
  9. # 通过id定位s输入框,并且输入内容'admin'
  10. driver.find_element_by_id("username").send_keys("admin")
  11. # 等待5秒
  12. time.sleep(5)
复制代码
运行结果:
在用户名输入框输入admin
[attach]134473[/attach]
①、通过name定位元素
agileone这个项目中,可以发现用户名的输入框,其中name的值为‘username,则可以通过find_element_by_name("wd")获取到输入框。
[attach]134474[/attach]
代码部分:
  1. from selenium import  webdriver
  2. import time
  3. driver=webdriver.Chrome(r"E:\webdriver\chromedriver.exe")
  4. driver.get(r"https://www.baidu.com/")
  5. time.sleep(3)
  6. driver.find_element_by_name('wd').send_keys('建党100周年')
  7. driver.find_element_by_id('su').click()
复制代码
运行结果:
[attach]134475[/attach]
3、通过tag_name定位元素
分析公告管理页面发现,‘内容’的输入框的tag为‘iframe’。通过
  1. find_element_by_tag_name('iframe')定位到输入框。
复制代码
[attach]134476[/attach]
代码如下:
  1. from selenium import webdriver
  2. from time import sleep
  3. # 加载驱动文件的路径
  4. driver=webdriver.Chrome(r'C:\webdriver\chromedriver.exe')
  5. # 打开浏览器
  6. driver.get('http://localhost:8081/agileone/')
  7. # 通过以下3行代码完成登录操作
  8. driver.find_element_by_id('username').send_keys('admin')
  9. driver.find_element_by_id('password').send_keys('admin')
  10. driver.find_element_by_id('login').click()
  11. sleep(3)
  12. #通过by_partial_link_text定位到公告管理,并且单击进入对应的页面
  13. driver.find_element_by_partial_link_text('公告管理').click()
  14. sleep(3)
  15. #通过by_tag_name定位输入框
  16. driver.find_element_by_tag_name('iframe').send_keys('我是iframe')
  17. # 等待5秒
  18. sleep(5)
复制代码
代码运行结果如下:
[attach]134477[/attach]
4、通过class_name定位元素
可以通过class的值为‘login-password’唯一定位到密码输入框。
[attach]134478[/attach]
对应的代码:
  1. from selenium import webdriver
  2. from time import sleep
  3. # 加载驱动文件的路径
  4. driver=webdriver.Chrome(r'C:\webdriver\chromedriver.exe')
  5. # 打开浏览器
  6. driver.get('http://localhost:8081/agileone/')
  7. # 通过class定位元素,并输入'admin'
  8. driver.find_element_by_class_name('login-password').send_keys('admin')
  9. # 等待5秒
  10. sleep(5)
复制代码
运行结果如下,明明框接收到了值。
[attach]134479[/attach]
5、通过link_text
在百度页面,‘新闻’等链接有文本信息,比如可以通过文本内容为新闻,定位到新闻链接。
可以采用方法find_element_by_link_text(‘新闻’)。
[attach]134481[/attach]
  1. from selenium import webdriver
  2. from time import sleep
  3. # 加载驱动文件的路径
  4. driver=webdriver.Chrome(r'C:\webdriver\chromedriver.exe')
  5. # 打开浏览器
  6. driver.get(r'https://www.baidu.com/')
  7. # 通过link_text定位元素
  8. driver.find_element_by_link_text('新闻').click()
  9. # 等待5秒
  10. sleep(5)
复制代码
运行结果
[attach]134482[/attach]
6、通过partial_link_text
通过部分文本也可以定位到元素,比如‘新闻’中的‘闻’字。
代码如下:
  1. from selenium import webdriver
  2. from time import sleep
  3. # 加载驱动文件的路径
  4. driver=webdriver.Chrome(r'C:\webdriver\chromedriver.exe')
  5. # 打开浏览器
  6. driver.get(r'https://www.baidu.com/')
  7. # 通过partial_link_text定位元素
  8. driver.find_element_by_partial_link_text('闻').click()
  9. # 等待5秒
  10. sleep(5)
复制代码
运行结果如下:
[attach]134483[/attach]
7、通过css定位元素
css定位原理同上述,都是根据标签的属性来锁定元素,只是语法不同,但是可以完成更复杂的高级定位。
总结如下:
[attach]134484[/attach]
页面分析:
通过前面分析,我们知道百度的首页中,输入框的id为kw,那么对应的自动化脚本应该如下:
代码部分:
  1. #导入驱动文件
  2. from selenium import webdriver
  3. import time
  4. # 加载驱动文件的路径
  5. driver=webdriver.Chrome(r'C:\webdriver\chromedriver.exe')
  6. # 打开百度首页
  7. driver.get(r'https://www.baidu.com/')
  8. # 通过xpath定位搜索框,并输入'建党100周年'
  9. driver.find_element_by_css_selector('#kw').send_keys('建党100周年')
  10. # 等待5秒
  11. time.sleep(5)
复制代码
8、通过xpath定位元素
Xpath也是定位元素的一种方法,有自己的语法。
[attach]134485[/attach]
页面分析:
通过前面分析,我们知道百度的首页中,输入框的id为kw,那么对应的自动化脚本应该如下:
代码部分:
  1. #导入驱动文件
  2. from selenium import webdriver
  3. import time
  4. # 加载驱动文件的路径
  5. driver=webdriver.Chrome(r'C:\webdriver\chromedriver.exe')
  6. # 打开百度首页
  7. driver.get(r'https://www.baidu.com/')
  8. # 通过xpath定位搜索框,并输入'建党100周年'
  9. driver.find_element_by_xpath('//*[@id="kw"]').send_keys('建党100周年')
  10. # 等待5秒
  11. time.sleep(5)
复制代码
运行结果
[attach]134486[/attach]
Selenium自动化框架设计
框架结构:selenium+python+unittest+HTMLTestRunner,该框架可以直接套用于项目中。
1、项目目录结构[attach]134487[/attach]
1)一级目录一般是项目名称。
2)二级目录有具备的模块,如有a_regist模块,b_login模块等;同时把report报告目录和主程序runner.py也放在二级目录。
3)三级目录是python模块文件,建议取名为test_二级模块名.py。比如test_regist.py、test_login.py。
【注意:二级目录名称前面的a、b字符是为了改变程序运行的顺序,在实际项目中,结构清晰的框架,更方便维护和调用。】



作者: lsekfe    时间: 2021-9-18 11:25
2、框架运行原理
对于搭建python+selenium这样的框架来说:
首先有一个主入口模块,叫runner.py,运行此模块可以执行所有用例,类似于点击一下启动按钮。所有其他的用例和最后用例执行完生成的报告,都是依赖于runner.py。
runner.py中,首先要导入需要用到的库,比如unittest框架等,其次找到用例存放的路径,定义报告生成的格式,最后调用run方法运行测试用例,把结果写入报告。
整个框架在运行的时候,只需要运行runner.py这个主入口程序,其中关于这个程序主要实现:
1、通过unittest.defaultTestLoader.discover()方法收集所有的测试用例
2、构造测试报告,通过HTMLTestRunner指定报告生成的路径和名称
【备注:测试用例即在每个py文件的test开头的函数】
3、通过HTMLTestRunner的run方法,运行所有的测试用例
3、具体代码详解
=============================runner.py===============================
runner.py为主入口程序,即运行测试用例只需要点击该py文件即可。
  1. import unittest
  2. import time
  3. import os
  4. from HTMLTestRunner import  HTMLTestRunner
  5. test_dir = os.path.join(os.getcwd())  # 获取项目的根目录
  6. tests = unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py') # 收集所有的testcase
  7. runner = unittest.TextTestRunner(verbosity=2)
  8. now = time.strftime('%Y-%m-%d %H_%M_%S')  # 获取当前日期
  9. filename = test_dir+ '\\report\\'+now + '_result.html'  # 构造出完整的文件名路径
  10. fp = open(filename, 'wb')  # wb方式写入
  11. runner = HTMLTestRunner(stream=fp, title='测试报告', description='phpwind732项目用例执行情况',verbosity=2)  #构造runner
  12. runner.run(tests)  # 调用runner的run方法
复制代码



==========================test_register.py===========================
test_register.py是项目的一个注册页面,且以test开头命名符合runner.py中搜索用例的规则。所以该文件中包含需要的测试用例。
  1. import time
  2. import unittest
  3. import random
  4. from selenium import  webdriver
  5. username = 'wang'+str(random.randint(1,10000))
  6. class Test_Register(unittest.TestCase):
  7.     '''注册模块'''
  8.     @classmethod
  9.     def setUpClass(cls):
  10.         driver = webdriver.Chrome(r"e:\webdriver\chromedriver.exe")
  11.         driver.implicitly_wait(10)
  12.         driver.get(r"http://localhost:8081/phpwind732/register.php")
  13.         cls.driver=driver   #声明类属性

  14.     @classmethod
  15.     def tearDownClass(cls):
  16.         cls.driver.quit()

  17.     def setUp(self):
  18.         time.sleep(3) # 为了看到演示效果
  19.     def tearDown(self):
  20.         time.sleep(3)  # 为了看到演示效果

  21.     def test_00_regist(self):  #测试用例
  22.         '''测试注册用户名过短'''
  23.         driver=self.driver
  24.         time.sleep(3)
  25.         driver.find_element_by_css_selector('input[onclick*="unpermit()"]').click()
  26.         time.sleep(3)
  27.         driver.find_element_by_id("regname").send_keys('t')
  28.         time.sleep(3)
  29.         driver.find_element_by_id("regpwd").send_keys("123456")
  30.         driver.find_element_by_id('regpwdrepeat').send_keys('123456')
  31.         driver.find_element_by_id('regemail').send_keys(username+'@qq.com')
  32.         driver.find_element_by_css_selector('input[type="submit"]').click()
  33.         time.sleep(3)
  34.         msg=driver.find_element_by_id('regname_info').text
  35.         time.sleep(3)
  36.         self.assertIn("用户名长度错误",msg)

  37.     def test_01_regist(self):
  38.         '''测试注册成功'''
  39.         driver = self.driver
  40.         time.sleep(3)
  41.         driver.find_element_by_css_selector('input[onclick*="unpermit()"]').click()
  42.         time.sleep(3)
  43.         driver.find_element_by_id("regname").send_keys(username)
  44.         time.sleep(2)
  45.         driver.find_element_by_id("regpwd").send_keys("123456")
  46.         driver.find_element_by_id('regpwdrepeat').send_keys('123456')
  47.         driver.find_element_by_id('regemail').send_keys('Ms'+username+'@qq.com')
  48.         time.sleep(3)
  49.         driver.find_element_by_css_selector('input[type="submit"]').click()
  50.         time.sleep(3)
  51.         msg = driver.find_element_by_css_selector('form tr:nth-of-type(1) td:nth-of-type(1)').text
  52.         time.sleep(3)
  53.         self.assertIn("注册成功", msg)

  54. if __name__ == '__main__':
  55.     unittest.main(verbosity=2) #运行类里面的方法
复制代码


==========================test_login.py==============================
test_login.py是项目的登录页面,且文件命令以test开头,符合用例文件的命令规则,即该文件里面包含需要执行的测试用例。
  1. import time
  2. import unittest
  3. from selenium import  webdriver
  4. import a_register.test_register as regist

  5. username=regist.username
  6. class Test_Login(unittest.TestCase):
  7.     '''登录模块'''
  8.     @classmethod
  9.     def setUpClass(cls):
  10.         driver = webdriver.Chrome(r"e:\webdriver\chromedriver.exe")
  11.         driver.implicitly_wait(10)
  12.         driver.get(r"http://localhost:8081/phpwind732/login.php")
  13.         cls.driver=driver   #声明类属性

  14.     @classmethod
  15.     def tearDownClass(cls):
  16.         cls.driver.quit()

  17.     def setUp(self):
  18.         time.sleep(3) # 为了看到演示效果
  19.     def tearDown(self):
  20.         time.sleep(3)  # 为了看到演示效果
  21.         self.driver.refresh()

  22.     def test_00_login(self):  #测试用例
  23.         '''测试登录成功'''
  24.         driver=self.driver
  25.         time.sleep(3)
  26.         driver.find_element_by_css_selector('input[name="pwuser"]').send_keys(username)
  27.         driver.find_element_by_css_selector('input[name="pwpwd"]').send_keys('123456')
  28.         driver.find_element_by_css_selector('input[name="submit"]').click()
  29.         time.sleep(5)
  30.         msg=driver.find_element_by_css_selector('a[href*="login"]').text
  31.         self.assertIn("退出",msg)
  32. if __name__ == '__main__':
  33.     unittest.main(verbosity=2) #运行类里面的方法
  34. 4、项目框架维护
复制代码

如何维护自动化测试用例?【增删改用例】
在已有框架的基础上,每个测试场景都是一个独立的.py文件。假如,需要增加一个查询的用例,则根据模块命令规则新建test_query.py,在该模块中,用selenium元素获取方法加元素定位方法完成业务操作,比如通过id找到输入框,通过send_keys方法输入内容,通过class的值等定位查询按钮,点击查询按钮,完成页面的查询操作等操作,在该方法里面同样可以增加断言来判断是否查询成功,并把结果记录到报告。
该自动化的框架结构比较简单,引用了很多封装好的库,如果想研究直接继承过来的类或方法,可以在python的lib库里找到unittest这个文件夹,里面包含了unittest的所有类和方法的实现,方便大家对底层封装的理解。


作者: 千里    时间: 2021-9-18 15:04
angileone我一直没有部署成功




欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2