Page Object是Selenium自动化测试项目开发实践的最佳设计模式之一,通过对界面元素的封装减少冗余代码,同时在后期维护中,若元素定位发生变化,只需要调整页面元素封装的代码,提高测试用例的可维护性。
本项目以163邮箱登录为例,163登录脚本(非PO模式)请查看博客中的随笔信息。
1、项目目录结构及相关介绍
test_programe 测试项目
- driver:用于存放驱动
- mail:用于存放163登录项目的测试用例、测试报告以及测试数据等
- run_all_test.py:用于运行项目自动化用例
mail目录
- data:存放测试数据
- report:存放HTML测试不报告,其中该目录下的image目录用于存放测试过程中的截图
- test_case:用于存放测试用例
test_case目录
- model:存放配置函数及公共类
- page_object:用于存放页面对象
- login_case.py:测试对象用例
2、编写公共模块:
编写驱动文件... est_programemail est_casemodeldriver.py
1 from selenium.webdriver import Remote 2 from selenium import webdriver 3 #启动浏览器驱动 4 def browser(): 5 driver = webdriver.Chrome() 6 ''' 7 #可以启动到远程主机中,运行自动化测试 8 host = '127.0.0.1:4444' #运行主机:端口号(本机默认:127.0.0.1:4444) 9 dc = {'browserName': 'chrome'} #指定浏览器 10 driver = Remote(command_execute='http://' + host + '/wd/hub', 11 desired_capabilities=dc) 12 ''' 13 return driver 14 ''' 15 #用于测试该脚本是否有效 16 if __name__ == '__main__': 17 dr = browser() 18 '''
编写测试公共类... est_programemail est_casemodelmyunit.py
from time import sleep from .function import insert_img import unittest from .driver import browser class MyTest(unittest.TestCase): def setUp(self): self.driver = browser() self.driver.implicitly_wait(10) self.driver.maximize_window() def tearDown(self): self.driver.quit()
定义截图函数... est_programemail est_casemodelfunction.py
1 from selenium import webdriver 2 import os 3 #截图函数 4 def insert_img(driver, file_name): 5 base_dir = os.path.dirname(os.path.dirname(__file__)) 6 #print(base_dir) 7 base_dir = str(base_dir) 8 #print(base_dir) 9 base_dir = base_dir.replace('\','/') 10 #print(base_dir) 11 base = base_dir.split('/mail')[0] 12 #print(base) 13 file_path = base + '/mail/report/image/' + file_name 14 driver.get_screenshot_as_file(file_path) 15 16 ''' 17 #用于验证该脚本是否有效 18 if __name__ == '__main__': 19 driver = webdriver.Chrome() 20 driver.get('http://www.baidu.com') 21 insert_img(driver, 'baidu.jpg') 22 driver.quit() 23 '''
3、编写Page Object
创建基础类... est_programemail est_casepage_objectase.py
1 from selenium import webdriver 2 from selenium.webdriver.common.by import By 3 from time import sleep 4 import unittest 5 #基本层 6 class Base(object): 7 8 9 def __init__(self, driver, base_url = 'http://mail.163.com'): 10 self.driver = driver 11 self.base_url = base_url 12 self.timeout = 30 13 14 def _open(self, url): 15 url_ = self.base_url + url 16 #print(url_) 17 self.driver.maximize_window() 18 self.driver.get(url_) 19 sleep(2) 20 assert self.driver.current_url == url_, 'Did ont land on %s' % url_ 21 22 def open(self): 23 self._open(self.url) 24 25 #*参数个数不是固定的(By.ID, 'kw') 26 def find_element(self, *loc): 27 return self.driver.find_element(*loc) 28 29 def iframe(self, iframeid): 30 return self.driver.switch_to.frame(iframeid) 31 32 def iframe_out(self): 33 return self.driver.switch_to.default_content() 34 35
创建163邮箱登录对象类... est_programemail est_casepage_objectlogin_page.py
1 from selenium.webdriver.common.action_chains import ActionChains 2 from selenium.webdriver.common.by import By 3 from time import sleep 4 from .base import Base 5 6 #页面对象(PO)登录页面 7 class LoginPage(Base): 8 url = '/' 9 login_iframe_loc = 'x-URS-iframe' 10 login_username_text_loc = (By.NAME, 'email') 11 login_password_text_loc = (By.NAME, 'password') 12 login_button_loc = (By.ID, 'dologin') 13 login_erro_hint_loc = (By.CLASS_NAME, 'ferrorhead') 14 15 #把每一个元素封装成一个方法 16 def login_iframe(self): 17 self.iframe(self.login_iframe_loc) 18 19 def login_iframe_out(self): 20 self.iframe_out() 21 22 def login_username(self, text): 23 self.find_element(*self.login_username_text_loc).send_keys(text) 24 25 def login_password(self, text): 26 self.find_element(*self.login_password_text_loc).send_keys(text) 27 28 def login_button(self): 29 self.find_element(*self.login_button_loc).click() 30 31 def login_error_hint(self): 32 self.login_iframe() 33 return self.find_element(*self.login_erro_hint_loc).text 34 self.login_iframe_out() 35 36 def login_action(self, username, password): 37 self.login_iframe() 38 self.login_username(username) 39 self.login_password(password) 40 self.login_button() 41 self.login_iframe_out()
创建163邮箱登录成功后对象类... est_programemail est_casepage_objectmail_page.py
1 from selenium.webdriver.common.action_chains import ActionChains 2 from selenium.webdriver.common.by import By 3 from time import sleep 4 from .base import Base 5 6 class MailPage(Base): 7 url = '/' 8 login_success_user_loc = (By.ID, 'spnUid') 9 10 def login_success_user(self): 11 return self.find_element(*self.login_success_user_loc).text
4、编写测试用例
创建mail登录类... est_programemail est_caselogin_case.py
1 from time import sleep 2 import unittest, random, sys 3 from model import myunit, function 4 from page_object.login_page import LoginPage 5 from page_object.mail_page import MailPage 6 sys.path.append('./model') 7 sys.path.append('./page_obj') 8 9 class LoginTest(myunit.MyTest): 10 11 def test_login_user_pwd_null(self): 12 '''用户名、密码为空登录''' 13 po = LoginPage(self.driver) 14 po.open() 15 po.login_action('','') 16 sleep(2) 17 self.assertEqual(po.login_error_hint(),'请输入帐号') 18 function.insert_img(self.driver, 'user_pwd_null.jpg') 19 20 def test_login_pwd_null(self): 21 '''密码为空登录''' 22 po = LoginPage(self.driver) 23 po.open() 24 po.login_action('abc','') 25 sleep(2) 26 self.assertEqual(po.login_error_hint(),'请输入密码') 27 function.insert_img(self.driver, 'pwd_null.jpg') 28 29 def test_login_user_pwd_error(self): 30 '''用户名或密码错误''' 31 po = LoginPage(self.driver) 32 po.open() 33 character = random.choice('zyxwvutsrqponmlkjihgfedcba') 34 username = "test" + character 35 po.login_action(username,"$#%#") 36 sleep(2) 37 #print(po.login_error_hint()) 38 self.assertEqual(po.login_error_hint(),'帐号或密码错误') 39 function.insert_img(self.driver, "user_pwd_error.jpg") 40 41 def test_login_success(self): 42 '''用户名、密码正确,登录成功''' 43 po = LoginPage(self.driver) 44 po.open() 45 user = "ldq791918813" 46 po.login_action(user,"xiuxiu060801zhu") 47 sleep(2) 48 po2 = MailPage(self.driver) 49 #print(po2.login_success_user()) 50 self.assertEqual(po2.login_success_user(),user+"@163.com") 51 function.insert_img(self.driver, "success.jpg")
5、执行测试用例
创建用例执行代码... est_programe
1 import unittest, time 2 from HTMLTestRunner import HTMLTestRunner 3 from email.mime.text import MIMEText 4 from email.header import Header 5 import smtplib, os 6 7 #发送测试报告,需要配置你的邮箱账号 8 def send_mail(file_new): 9 f = open(file_new, 'rb') 10 mail_body = f.read() 11 f.close() 12 msg = MIMEText(mail_body, 'html', 'utf-8') 13 msg['Subject'] = Header("自动化测试报告", 'utf-8') 14 msg['From']= 'ldq791918813@163.com' 15 msg['To']= '791918813@qq.com' 16 smtp = smtplib.SMTP() 17 smtp.connect("smtp.163.com") 18 smtp.login("ldq791918813@163.com", "密码") 19 smtp.sendmail("ldq791918813@163.com","791918813@qq.com",msg.as_string()) 20 smtp.quit() 21 print('email has send out!') 22 23 #查找测试报告目录,找到最新生成的测试报告文件 24 def new_report(testreport): 25 lists = os.listdir(testreport) 26 lists.sort(key=lambda fn: os.path.getmtime(testreport + '\' + fn)) 27 file_new = os.path.join(testreport, lists[-1]) 28 print(file_new) 29 return file_new 30 31 #指定测试用例为当前文件夹下的test_case目录 32 test_dir = './mail/test_case' 33 test_report = 'D:\sublimePython\test_programe\mail\report' 34 discover = unittest.defaultTestLoader.discover(test_dir, pattern = '*_case.py') 35 36 if __name__ == "__main__": 37 38 now = time.strftime("%Y-%m-%d %H_%M_%S") 39 filename = test_report + '/' + now + 'result.html' 40 fp = open(filename, 'wb') 41 #runner = unittest.TextTestRunner() 42 runner = HTMLTestRunner(stream=fp, 43 title='测试报告', 44 description="运行环境:windows 7, Chrome") 45 runner.run(discover) 46 fp.close() 47 48 new_report = new_report(test_report) 49 send_mail(new_report)
6、HTML测试报告:
7、截图信息: