测试框架主要是对代码解耦,提高代码复用率,UI自动化比较经典的设计模式是使用的PO模式,指的是所有当前页面的控件和元素都为类或者对象的属性,我理解的PO模式分为三层,第一层是存放页面公共方法,是把通过id、xpath、css等等位方式封装成通用的元素定位方式。第二层是存放页面操作,继承页面公用方法,对页面进行操作,比如点击click()、输入值send_keys()之类的。第三层就是存放测试脚本
以进销存系统登录界面为例:
是第一层存放公共方法:page目录下base_page.py
第一个__init__方法 这里就是初始化需要浏览器驱动,传递driver,第二个方法baseFindElement是对元素定位进行封装,传递的参数loc是一个元组,*loc是对元组进行解包。传递参数时只需要把元组(定位方式,值)传递过去就可以了。这里使用的WebDriverWait是显式等待,设置的等待时长时10秒,每0.5秒定位一次。
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support.select import Select
class BasePage():
def __init__(self,driver):
self.driver=driver
#定位元素
def baseFindElement(self,loc):
return WebDriverWait(self.driver, 10,0.5).until(lambda x: x.find_element(*loc))
第二层方法:页面操作方法,page目录下的login_page.py
login_page继承了BasePage,把每项操作涉及的定位方式和值存放在变量中,调用父类里面定位元素的通用方法,输入用户名、密码、验证码在点击登录按钮。
在check_login_status中对登录结果做判断,定位到登录后界面的admin,返回True,定位不到返回False。
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
from page.base_page import BasePage
class LoginPage(BasePage):
username = (By.ID, "username") #用户名
password = (By.ID, "password") #密码
verify = (By.ID, "verifycode") #验证码
login_button = (By.XPATH, "//button[contains(@onclick,'doLogin')]") #登录按钮
flag = (By.XPATH, "//a[contains(text(),'admin')]") #登录后页面元素定位
def login_action(self,name,pwd,ver):
self.baseFindElement(self.username).send_keys(name)
self.baseFindElement(self.password).send_keys(pwd)
self.baseFindElement(self.verify).send_keys(ver)
self.baseFindElement(self.login_button).click()
def check_login_status(self):
try:
data = self.baseFindElement(self.flag).text
except TimeoutException:
print("-------------login false----------------")
return False
if "admin" in data:
print("-------------login success-------------")
return True
else:
print("-------------login false----------------")
return False
第三层是测试脚本层 testcases目录下的test_login.py
因为每进行一次页面操作,都需要打开获取驱动,打开浏览器,输入url,还有关闭浏览器,所以在common目录下创建一个page_util方法,方便后续调用。这块就是unittest的基于方法的测试夹具。获取浏览器驱动。
import unittest
from selenium import webdriver
class PageUtil(unittest.TestCase):
def setUp(self) -> None:
self.driver = webdriver.Chrome()
self.driver.get("http://192.168.47.15:8080/woniusales/")
self.driver.maximize_window()
def tearDown(self) -> None:
self.driver.quit()
testcases目录下的test_login.py
test_login继承了PageUtil类,这样可以在执行方法前,先执行setup方法,获取驱动,打开登录地址。导入LoginPage类,来进行页面操作。因为LoginPage继承了BasePage,BasePage初始化时需要一个driver参数,所以要把driver的值传递过去。
实例对象lg调用login_action方法,执行登录操作。lg.check_login_status()获取登录后的验证结果True or False。然后对登录结果进行断言
from common.page_util import PageUtil
from page.login_page import LoginPage
class TestLogin(PageUtil):
def test_LoginSuccess(self):
lg = LoginPage(self.driver)
lg.login_action("admin","admin123","0000")
flag = lg.check_login_status()
self.assertTrue(flag)
def test_LoginFalse(self):
lg = LoginPage(self.driver)
lg.login_action("","admin123","0000")
flag = lg.check_login_status()
self.assertFalse(flag)