Selenium是目前业内最为核心的页面自动化测试的实现技术。全程是由JS来实现的浏览器交互。搭配到webdriver来实现完整的自动化UI测试的效果。
常规的自动化测试技术体系,测试框架是目前企业级应用最核心的形态。
主体的设计模式分为两种:
1.关键字驱动
2.POM模式
是所有测试框架的核心基础
适应场景:对于有多个项目在同时进行、公司内部是基于频繁的项目研发来实现营收的体系化。
关键字驱动是唯一一种可以以一套框架来适配多种不同类型的项目的形态。但是对于所有的被测项目而言,无法准确评估覆盖率。
Po(page object model) & kdt(Keyword driver testing):
1、PO模型更关注的页面、元素抽象成代码,在代码级别的复用上会简单些,但编码能力要求会更高一些。
2、关键字模型,更关注的是业务流程,其实很多企业也是如此,我们只需要在excel文件中讲测试用例维护好,而需要编写的脚本量非常小,如果页面有变动,只需要维护excel表格中的用例数据即可,而脚本基本不需要变动。
https://blog.csdn.net/weixin_42550871/article/details/108684948
POM是目前业内公认最佳的一种设计模式。是专门用于对应指定系统来量身打造的一套测试框架。基于一个系统打造单独的测试框架。
全程叫做页面对象模型,是将系统以页面来进行区分。
举例:你要实现一个用户信息修改的流程。
登陆→进入个人中心→修改个人信息并保存→再重新查看个人信息详情。
从POM角度:
1.进入登陆页面,实现页面的核心流程;
2.进入个人中心页面,实现修改个人信息的操作
3.进入个人信息页面,实现查看个人信息的操作
4.校验修改结果是否成功
在POM体系下,全程都是基于页面来考虑这个流程的执行连贯性,中间会关联多少页面,每个页面分别会执行哪些内容。以页面为导向。
POM一套新人根据页面对象更容易了解业务流程。
1.工程结构形态:
(1)代码与数据分离
(2)逻辑代码与测试代码分离
2.POM结构:
(1)基类:逻辑代码的部分,主要是生产一系列在页面对象中被调用的工具函数。本身作为一个工具库的存在。–base
(2)*页面对象类:逻辑代码的部分,结合实际的项目,提取所有的可被自动化执行的页面。类中包含页面的核心元素与页面的核心流程。–page_object
(3)测试用例类:测试代码部分,用于拼接各类页面对象,实现最终的测试流程。–test_case
(4)测试数据类:用于提取所有在实际测试过程中需要应用的数据内容。–data
简单的POM体系设计:请看源码
自动化测试的实现一定是要关联到核心业务来走的,没有关联业务的自动化是无法实现落地的。
base_page.py
# -*- coding:utf-8 -*-
#@time:2021-07-23 22:22:26
#@Author:Anonymous
#@file:base_page.py
"""
Base_page类是POM中的基类,主要用于提供常用的函数,为页面对象类进行服务。
元素定位:
输入
点击
访问url
等待
关闭
"""
from time import sleep
from selenium import webdriver
class BasePage:
#虚构driver对象
# driver=webdriver.Chrome()
#构造函数
def __init__(self,driver):
self.driver=driver
#访问url
def visit(self):
self.driver.get(self.url)
#元素定位
def locator(self,loc):
# return self.driver.find_element(name,value) #为了便于管理,设置成如下元组参数
return self.driver.find_element(*loc)
#输入
def input_(self,loc,txt):
self.locator(loc).send_keys(txt)
#点击
def click(self,loc):
self.locator(loc).click()
#等待
def wait(self,time_):
sleep(time_)
#关闭
login_page.py
# -*- coding:utf-8 -*-
#@time:2021-07-24 11:35:11
#@Author:Anonymous
#@file:login_page.py
"""
LoginPage类,专门用于实现登陆页面对象的文件。
主题内容包含:
1.核心的页面元素
账户、密码、登陆按钮
2.核心的业务流:
用户的登陆行为
"""
from base.base_page import BasePage
from selenium import webdriver
from selenium.webdriver.common.by import By
import pytest
class LoginPage(BasePage):
#核心元素
url='http://39.98.138.157/shopxo/index.php?s=/index/user/logininfo.html'
user=(By.NAME,'accounts') #name,value,做成元组,便于管理
pwd=(By.NAME,'pwd')
login_button=(By.XPATH,'//div/button[@type="submit"]')
#核心业务流
def login(self,username,password):
self.visit()
self.input_(self.user,username)
self.input_(self.pwd,password)
self.click(self.login_button)
#调试代码
if __name__ == '__main__':
driver=webdriver.Chrome()
username='zsw'
password='123456'
lp=LoginPage(driver)
lp.login(username,password)
pytest.main(['-sv','login_page.py'])
lp.wait(2)
driver.quit()
test_case.py
# -*- coding:utf-8 -*-
#@time:2021-07-24 12:59:55
#@Author:Anonymous
#@file:test_cases.py
import unittest
from page_object.login_page import LoginPage
from selenium import webdriver
#测试用例的设计
class TestCase(unittest.TestCase):
def test_1_login(self):
driver = webdriver.Chrome()
username = 'zsw'
password = '123456'
lp = LoginPage(driver)
lp.login(username, password)
if __name__ == '__main__':
unittest.main()
index_page.py 搜索手机
#@Author:Anonymous
#@file:index_page.py
"""
indxe_page页面对象,实现首页中关于商品搜索的流程
"""
from base.base_page import BasePage
from selenium import webdriver
from selenium.webdriver.common.by import By
class IndexPage(BasePage):
#核心元素
url='http://39.98.138.157/shopxo/'
search_input=(By.NAME,'wd')
search_button=(By.ID,'ai-topsearch')
#核心业务流
def search(self,txt):
self.visit()
self.input_(self.search_input,txt)
self.click(self.search_button)
if __name__ == '__main__':
driver = webdriver.Chrome()
txt='手机'
ip=IndexPage(driver)
ip.search(txt)
思考如何把登陆和搜索手机这二个业务关联起来,也就是登陆后,进入页面,搜索手机。
一个页面只封装一个页面对象模型,不要把不同页面放在一起,排列是根据业务组合,不是固定的。
组合的过程是在测试用例里组合,不是在页面对象里组合。
# -*- coding:utf-8 -*-
#@time:2021-07-24 12:59:55
#@Author:Anonymous
#@file:test_cases.py
import unittest
from time import sleep
from page_object.index_page import IndexPage
from page_object.login_page import LoginPage
from selenium import webdriver
#测试用例的设计
class TestCase(unittest.TestCase):
def test_1_login(self):
driver = webdriver.Chrome()
username = 'zsw'
password = '123456'
txt='包'
lp = LoginPage(driver)
lp.login(username, password)
# 关联的核心原理就是一个driver贯穿这个生命周期
ip=IndexPage(driver)
ip.search(txt)
sleep(3)
if __name__ == '__main__':
unittest.main()
# -*- coding:utf-8 -*-
#@time:2021-07-24 12:59:55
#@Author:Anonymous
#@file:test_cases.py
import unittest
from time import sleep
from page_object.index_page import IndexPage
from page_object.login_page import LoginPage
from selenium import webdriver
#测试用例的设计
class TestCase(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.driver=webdriver.Chrome()
cls.lp=LoginPage(cls.driver)
cls.ip=IndexPage(cls.driver)
@classmethod
def tearDownClass(cls) -> None:
cls.driver.quit()
def test_1_login(self):
username = 'zsw'
password = '123456'
txt='包'
self.lp.login(username, password)
# 关联的核心原理就是一个driver贯穿这个生命周期
self.ip.search(txt)
sleep(3)
#如上这样写,一条用例创建一个浏览器,第二个用例又会创建一个浏览器,
if __name__ == '__main__':
unittest.main()
下面这种写法,一个函数登陆,另一个搜索拆开写比较清晰,第一条用例执行完,
然后执行第二条,一个个走。
# -*- coding:utf-8 -*-
#@time:2021-07-24 12:59:55
#@Author:Anonymous
#@file:test_cases.py
import unittest
from time import sleep
from page_object.index_page import IndexPage
from page_object.login_page import LoginPage
from selenium import webdriver
#测试用例的设计
class TestCase(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.driver=webdriver.Chrome()
cls.lp=LoginPage(cls.driver)
cls.ip=IndexPage(cls.driver)
@classmethod
def tearDownClass(cls) -> None:
cls.driver.quit()
def test_1_login(self):
username = 'zsw'
password = '123456'
self.lp.login(username, password)
"""
# 关联的核心原理就是一个driver贯穿这个生命周期,
# 写在函数里或放在初始化类里
# 一个函数登陆,另一个搜索拆开写比较清晰,第一条用例执行完,
然后执行第二条,一个个走。
"""
def test_2_search(self):
txt='包'
self.ip.search(txt)
sleep(3)
#如上这样写,一条用例创建一个浏览器,第二个用例又会创建一个浏览器,
if __name__ == '__main__':
unittest.main()
用户名密码,不想写在这里,想创建一个单独管理,在data目录下,创建user.yaml
ddt安装
安装pyyaml
python yml文件需要导入库 pip install pyyaml
安装ddt
方法一:
1、按win+R 进入cmd
2、pip install ddt
方法二:
1、打开pycharm
2、file—settings—project—project interpreter—–输入ddt–安装即可
编辑data/user.yaml
-
username : aaa
password : '1234567'
-
username : xuzhu666
password : '123456'
编辑test_case_for_search.py
# -*- coding:utf-8 -*-
#@time:2021-07-24 12:59:55
#@Author:Anonymous
#@file:test_cases.py
import unittest
from time import sleep
from page_object.index_page import IndexPage
from page_object.login_page import LoginPage
from selenium import webdriver
from ddt import ddt,file_data,data,unpack
#测试用例的设计
@ddt
class TestCase(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.driver=webdriver.Chrome()
cls.lp=LoginPage(cls.driver)
cls.ip=IndexPage(cls.driver)
@classmethod
def tearDownClass(cls) -> None:
cls.driver.quit()
@file_data('../data/user.yaml')
def test_1_login(self,username,password):
#用户名密码,不想写在这里,想创建一个单独管理,创建user.yaml
self.lp.login(username, password)
sleep(3)
"""
# 关联的核心原理就是一个driver贯穿这个生命周期,
# 写在函数里或放在初始化类里
# 一个函数登陆,另一个搜索拆开写比较清晰,第一条用例执行完,
然后执行第二条,一个个走。
"""
@data('手机','衣服','电脑')
def test_2_search(self,txt):
self.ip.search(txt)
sleep(3)
#如上这样写,一条用例创建一个浏览器,第二个用例又会创建一个浏览器,
if __name__ == '__main__':
unittest.main()
DDT+Yaml或者是常规的DDT+DATA的形态来实现数据驱动
更换ip做爬虫,ChromeOptions的配置中设置代理信息