PO模式全称Page Object Model ,是一种试用于UI自动化层面的分层设计模型。
page:存放页面元素的操作步骤
from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.by import By from tools.display_wait import display_wait from page_locator.login.login_page_locator import LoginPageLocator as loc class LoginPage(): '''登录界面''' def __init__(self, driver): self.driver = driver def login(self, username, pwd, remember_user=False): WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((loc.zt_protocol))) # # 点击组团推推广者规范 self.driver.find_element(*loc.zt_protocol).click() # 输入用户名 self.driver.find_element(*loc.input_usernane).send_keys(username) # 输入密码 self.driver.find_element(*loc.input_pwd).send_keys(pwd) # 点击登录 self.driver.find_element(*loc.click_button).click() def get_error_info(self): '''获取异常登录的错误提示信息''' xpath = "//div[@class='button']/span" display_wait(self.driver, By.XPATH, xpath) return self.driver.find_element_by_xpath(xpath).text
page_locator:存放定位元素的方式和元素对应的值,以元祖形式存储
'''存放定位元素的方式和值''' from selenium.webdriver.common.by import By class LoginPageLocator(): # 点击组团推推广者规范 zt_protocol = (By.XPATH,'//*[@id="agreement"]/div/div[3]') # 输入用户名 input_usernane = (By.CLASS_NAME,'userName') # 输入密码 input_pwd = (By.XPATH,'//input[@type="password"]') # 点击登录 click_button = (By.XPATH,'//div[@class="button"]')
由此可见:page = 页面操作步骤+页面元素
test_data:存放测试数据,正常场景数据和异常场景数据分开存放,分别数据类型是列表和字典
# 正常登录数据 normal_data = {"username":"1489088761@qq.com","pwd":"mg123456"} # 异常场景数据 exception_data = [ {"username":"148908876@qq.com","pwd":"mg123456","expected":"该邮箱尚未注册,请先注册"}, {"username":"1489088761@qq.com","pwd":"mg12345","expected":"用户名与密码不匹配,请重新输入"}, {"username":"1","pwd":"1","expected":"请输入正确的邮箱号"}, ]
testcase:存放测试用例,testcase=测试页面+测试数据,测试用例里面只有方法的调用和断言,体现一种出,高内聚低偶和。
import unittest from selenium import webdriver from page.login.login_page import LoginPage from page.home.home_page import HomePage from test_data.common.common_data import login_url from test_data.login.login_data import normal_data, exception_data from ddt import ddt, data @ddt class TestLogin(unittest.TestCase): def setUp(self): self.driver = webdriver.Chrome() self.driver.maximize_window() self.driver.get(login_url) self.lg = LoginPage(self.driver) def test_login_success(self): '''正常登录''' try: # 输入用户名,密码,登录 self.lg.login(normal_data['username'], normal_data['pwd']) # 断言首页是否有退出这个元素 self.assertTrue(HomePage(self.driver).isEcist_logout_ele()) except Exception as e: print('出现异常是:{}'.format(e)) @data(*exception_data) def test_error_format_login(self, data): '''异常用例3条:未注册的邮箱,密码错误,错误的邮箱号''' try: self.lg.login(data['username'], data['pwd']) print(data['expected']) self.assertEqual(self.lg.get_error_info(), data['expected'], '测试失败') print(self.lg.get_error_info()) except Exception as e: print('出现异常是:{}'.format(e)) def tearDown(self): self.driver.quit() if __name__ == '__main__': unittest.main()
tools:里面存放一些公共方法:
如上传文件的方法:
'''实现非input标签上传文件,调用此方法需要打开windows上传文件的系统窗口再调用''' import win32gui import win32con def upload_file(file_path): ''' :param file_path:上传文件的路径 :return: ''' dialog = win32gui.FindWindow("#32770", "打开") comboxex32 = win32gui.FindWindowEx(dialog, 0, "ComboBoxEx32", None) combox = win32gui.FindWindowEx(comboxex32, 0, "ComboBox", None) edit = win32gui.FindWindowEx(combox, 0, "Edit", None) button = win32gui.FindWindowEx(dialog, 0, "Button", "打开(&0)") win32gui.SendMessage(edit, win32con.WM_SETTEXT, None, file_path) win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button) upload_file(r'C:UsersadminDesktopScreenshotmvcSnipaste_2019-12-26_20-59-19.png')
显示等待的方法:
'''显示等待,等待元素可见''' from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.by import By def display_wait(driver, location_mthod, value): ''' :param driver: driver对象 :param location_mthod: 定位方式,如:By.XPATH :param value: 对应的元素,如:id = 'TANGRAM__PSP_10__footerULoginBtn' :return: ''' WebDriverWait(driver, 10).until(EC.visibility_of_element_located((location_mthod, value)))
全部详细文件夹规划如图: