前言: 本小白在学习POM的时候看了很多文章+书+视频,终于有一点理解了(泪目TT)
很多文章都不是真的适合小白(生气^^)视频又很长很啰嗦so致力于写出真正适合小白看的(其实是自己的理解and经验)
先介绍 : POM(Page Pbject Model) ,即页面对象模型,就是一个web自动化常用的设计模式,
为什么用POM模式?
之前写谷歌搜索,网站登录等等的时候,我们是把所有的操作都写在一块(写在了同一个py文件),那对于一个大项目,有很多很多操作,当以后某个元素更新了,定位什么的全部都要改改改! 很麻烦呀,并且利用率不高,复用也不好。
这时候就出现了POM!( 其实说白了我感觉就是Java的封装
其思想理念就是 : 分层~封装~ 把每一个页面当做每一个对象
POM分四层
先看图:把这四层(包)建在你自己的文件下面 ,后面你要写什么就在对应的包里面新建py文件就行了; (这里我只用到了Base层,pageobject层和testcase层,report是用来放allure报告的先不用管,所以图里就三层)
1.base层 (基类
定义类base_page : 包含提取每个页面相同的数据 ,包括:
相同的属性 : 浏览驱动实例对象
相同方法/操作 : 比如说都要点击,都要输入, 都要定位元素,关闭浏览器等一些可重复利用的常规操作.....
2.pageobject层
我们项目,比如测试一个网站,这个网站会有很多页面,那么每个页面除了base层的相同属性和操作之外,还有各自的自己的一些数据(自己的元素和操作)
那么我们针对每一个页面去定义一个类:
比如 : 登录页面 ,创建 login_page.py, 然后在这里面定义LoginPage类
再比如 : 搜索页面, 创建search_page.py,然后在这里面定义SearchPage类
以此类推,反正你就看是什么页面,自己去创建和命名就行了
3.testcase层(test_开头)
用例层, 下面封装的是某些测试用例 (描述业务流程)
要test_开头的py文件哦!!! 根据你的业务需要去命名就OK
主方法可以直接写在这层; 也可以单独写一个main.py,用pytest框架运行此测试用例,并且输出测试报告。
4.testdata层
数据层 , 涵盖全局变量+测试用例数据
案例
以测试https://www.saucedemo.com/这个网站的登录和购物为例子
1.base层----我命名的包名为BasePage,里面新建文件名为base_page,写的类名为BasePages
# 这是个定义类,包含每个页面相同的数据:相同属性,相同方法
class BasePages:
# 新建驱动对象
def __init__(self, driver):
try:
self.driver = driver
except Exception:
raise NameError("No Chrome Found")
# 访问网页(加载项目地址)
def open(self, url):
if url != "":
self.driver.get(url)
self.driver.maximize_window()
else:
raise ValueError("No URL provided,Please provide a url")
# 元素定位
# loc=(By.ID,"xxx"),用一个元组的方式来传递参数,表示用by什么方法定位,不含真正的值哦
# 即将所有元素定位方法封装到locator方法中。
def locator(self, loc):
# 因为loc有两个元素,所以会用到*
return self.driver.find_element(*loc)
# 输入
# locator(loc)是得到元素定位,send_keys(value)是之后输入真正的值
def input(self, loc, value):
self.locator(loc).send_keys(value)
# 点击
# locator(loc)是定位登录框元素 , 这里不需要往里面输入值,就不需要value了
def click(self, loc):
self.locator(loc).click()
2.1pageobject层----我命名的包名为PageObject,里面新建文件名为login_page,写的类名为LoginPage
# 导入前面的类
from POMDemo.BasePage.base_page import BasePages
from selenium.webdriver.common.by import By
# (BasePages)是继承基础类的所有方法
class LoginPage(BasePages):
# 核心元素
# url元素
url = 'https://www.saucedemo.com/'
# 用户名输入框元素,这里对应了前面的loc=(By.ID,"xxx")格式来写
user_ele = (By.ID, "user-name")
# 密码输入框元素
pwd_ele = (By.ID, "password")
# 登录按钮元素
login_btn = (By.ID, "login-button")
# 核心流程 登录
def login(self, username, password):
# 访问网页-把url传进去
self.open(self.url)
# 输入用户名
self.input(loc=self.user_ele, value=username)
# 输入密码
self.input(self.pwd_ele, password)
# 点击登录-传入按钮
self.click(self.login_btn)
这里注意: 代码最前面的一行是导入上一个类,是相对路径,别写错了; 比如我这个POMDemo是在总项目Selenium下面的,所以是from POMDemo.BasePage.base_page import BasePages,如果你的就是最大的项目,就直接from BasePage.base_page import BasePages
2.2还是pageobject层----还是PageObject这个包下,新建文件名为shop_page,写的类名为ShopPage
(新手小白可以只做2.1~解说一下2.1是登录页面,可以先跳过2.2~,我这里记录一下我做了两个页面,这个2.2是购物页面)
from POMDemo.BasePage.base_page import BasePages
from selenium.webdriver.common.by import By
class ShopPage(BasePages):
def shopping(self):
# 核心元素
url = "http://www.saucedemo.com/inventory.html"
btn1 = ("By.ID", "add-to-cart-sauce-labs-backpack")
btn2 = ("By.ID", "add-to-cart-sauce-labs-bike-light")
btn3 = ("By.ID", "add-to-cart-sauce-labs-bolt-t-shirt")
btn4 = ("By.ID", "remove-sauce-labs-bolt-t-shirt")
btn5 = ("By.CLASS_NAME", "shopping_cart_link")
# 核心操作
# 模拟点击加入三个商品.再取消最后一个商品,最后点击购物按钮,跳转到下一个页面,一共5个步骤
def shopping(self):
self.open(self.url)
self.on_click(self.btn1)
self.on_click(self.btn2)
self.on_click(self.btn3)
self.on_click(self.btn4)
self.on_click(self.btn5)
3.testcase层----我命名的包名为test_page,里面新建文件名为test_shopping,写的类名为TestShopping
# 测试用例-->业务流程
# 导入前面的类
from POMDemo.PageObject.shop_page import ShopPage
from POMDemo.PageObject.login_page import LoginPage
import pytest
from selenium import webdriver
class TestShopping:
driver = webdriver.Chrome()
# 登录 --实例化LoginPage这个类
# 这里括号里面必须传driver,因为实例化这个LoginPage类时会去找它,然后去login_page.py里面发现
# class LoginPage(BasePages)又继承了BasePages,又再去base_page.py找
# 发现了,确实是def __init__(self, driver)需要有driver!!
my_login = LoginPage(driver)
user = "standard_user"
pwd = "secret_sauce"
# 调用LoginPage里面的login方法,因为login方法是核心登录流程,把真正的值传进去
my_login.login(user, pwd)
# 购物
# 问题: 这里会新建两个驱动对象,两个页面,一个是登录的,一个是购物的,导致网页的不连贯性
# 解决办法: 只保持一个测试的驱动对象
shop = ShopPage(driver)
shop.shopping()
if __name__ == '__main__':
pytest.main(['-vs'])
不做2.2的把购物那里的代码删了就行
总结
大白话理解 : 我们把这个项目分层写,一样的操作我们写一个包里面,各自不一样的地方也写在一个包里面,但这包里面就分开写XXpage,登录页面就Login_page,购物页面就shop_page,你要写几个页面就几个XXpage,然后最后就是test的包,主要来执行这些业务流程的这么的一个包
尾声:
参考文章:https://www.cnblogs.com/FBGG/p/16552644.html
参考视频:【详细python自动化测试实战POM模式分层封装框架视频-哔哩哔哩】 https://b23.tv/YcK51AG (作者码尚开发,这个视频比较多,可以直接倍速看最后的实战视频,老师讲的挺细的)
【自动化测试之POM设计模式2-哔哩哔哩】 https://b23.tv/DFa1MOA(作者勿需懂,这个是本篇文章的实战教学视频,一模一样的,一步步跟着做,有3个视频)