selenium实例:unittest框架+PO开发模式
这是《selenium2+python学习总结》的升级版。
- 1. 项目结构

- 2. 项目代码
1) globalparameter.py
# coding:utf-8
__author__ = 'helen'
import time,os
'''
配置全局参数
'''
# 项目的绝对路径(因为 windows执行时需要绝对路径才能执行通过)
# project_path = "D:\\for2017\\SPframework-Helen_2.0\\"
# 获取项目路径
project_path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)[0]), '.'))
print project_path
# 测试用例代码存放路径(用于构建suite,注意该文件夹下的文件都应该以test开头命名)
test_case_path = project_path+"\\src\\test_case"
# excel测试数据文档存放路径
test_data_path = project_path+"\\data\\testData.xlsx"
# 日志文件存储路径
log_path = project_path+"\\log\\mylog.log"
print u'日志路径:'+log_path
# 测试报告存储路径,并以当前时间作为报告名称前缀
report_path = project_path+"\\report\\"
report_name = report_path+time.strftime('%Y%m%d%H%S', time.localtime())
# 异常截图存储路径,并以当前时间作为图片名称前缀
img_path = project_path+"\\error_img\\"+time.strftime('%Y%m%d%H%S', time.localtime())
# 设置发送测试报告的公共邮箱、用户名和密码
smtp_sever = 'mail.**.com' # 邮箱SMTP服务,各大运营商的smtp服务可以在网上找,然后可以在foxmail这些工具中验正
email_name = "SDS@**.com" # 发件人名称
email_password = "****" # 发件人登录密码
email_To = '5047**0@qq.com;54*0016@qq.com;hel**ter@163.com' # 收件人
2) log.py
# coding:utf-8
__author__ = 'helen'
import logging
from config import globalparameter as gl
'''
配置日志文件,输出INFO级别以上的日志
''' class log:
def __init__(self):
self.logname = "mylog" def setMSG(self, level, msg):
# 之前把下面定义log的一大段代码写在了__init__里面,造成了日志重复输出
# 此大坑,谨记谨记!!!!
logger = logging.getLogger()
# 定义Handler输出到文件和控制台
fh = logging.FileHandler(gl.log_path)
ch = logging.StreamHandler()
# 定义日志输出格式
formater = logging.Formatter("%(asctime)s %(levelname)s %(message)s' ")
fh.setFormatter(formater)
ch.setFormatter(formater)
# 添加Handler
logger.addHandler(fh)
logger.addHandler(ch)
# 添加日志信息,输出INFO级别的信息
logger.setLevel(logging.INFO)
if level=='debug':
logger.debug(msg)
elif level=='info':
logger.info(msg)
elif level=='warning':
logger.warning(msg)
elif level=='error':
logger.error(msg)
# 移除句柄,否则日志会重复输出
logger.removeHandler(fh)
logger.removeHandler(ch)
fh.close() def debug(self, msg):
self.setMSG('debug', msg) def info(self, msg):
self.setMSG('info', msg) def warning(self, msg):
self.setMSG('warning', msg) def error(self, msg):
self.setMSG('error', msg)
3) send_mail.py
# coding:utf-8
__author__ = 'helen'
import os,smtplib,os.path
from config import globalparameter as gl
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from src.common import log
'''
邮件发送最新的测试报告
''' class send_email:
def __init__(self):
self.mylog = log.log() # 定义邮件内容
def email_init(self,report,reportName):
with open(report,'rb')as f:
mail_body = f.read() # 创建一个带附件的邮件实例
msg = MIMEMultipart()
# 以测试报告作为邮件正文
msg.attach(MIMEText(mail_body,'html','utf-8'))
report_file = MIMEText(mail_body,'html','utf-8')
# 定义附件名称(附件的名称可以随便定义,你写的是什么邮件里面显示的就是什么)
report_file["Content-Disposition"] = 'attachment;filename='+reportName
msg.attach(report_file) # 添加附件
msg['Subject'] = '自动化测试报告:'+reportName # 邮件标题
msg['From'] = gl.email_name #发件人
msg['To'] = gl.email_To #收件人列表
try:
server = smtplib.SMTP(gl.smtp_sever)
server.login(gl.email_name,gl.email_password)
server.sendmail(msg['From'],msg['To'].split(';'),msg.as_string())
server.quit()
except smtplib.SMTPException:
self.mylog.error(u'邮件发送测试报告失败 at'+__file__) def sendReport(self):
# 找到最新的测试报告
report_list = os.listdir(gl.report_path)
report_list.sort(key=lambda fn: os.path.getmtime(gl.report_path+fn) if not os.path.isdir(gl.report_path+fn) else 0)
new_report = os.path.join(gl.report_path,report_list[-1])
# 发送邮件
self.email_init(new_report,report_list[-1])
4) excel_data.py
# coding:utf-8
__author__ = 'helen'
import xlrd
from src.common import log
from config.globalparameter import test_data_path
'''
读取excel文件
''' class excel:
def __init__(self):
self.mylog = log.log() def open_excel(self,file):
u'''读取excel文件'''
try:
data = xlrd.open_workbook(file)
return data
except Exception, e:
self.mylog.error(u"打开excel文件失败") def excel_table(self,file, sheetName):
u'''装载list'''
data = self.open_excel(file)
# 通过工作表名称,获取到一个工作表
table = data.sheet_by_name(sheetName)
# 获取行数
Trows = table.nrows
# 获取 第一行数据
Tcolnames = table.row_values(0)
lister = []
for rownumber in range(1,Trows):
row = table.row_values(rownumber)
if row:
app = {}
for i in range(len(Tcolnames)):
app[Tcolnames[i]] = row[i]
lister.append(app)
return lister def get_list(self,sheetname):
try:
data_list = self.excel_table(test_data_path, sheetname)
assert len(data_list)>=0,u'excel标签页:'+sheetname+u'为空'
return data_list
except Exception as e:
self.mylog.error(u'excel标签页:'+sheetname+u'为空')
raise e
5) Base_Page.py
# coding:utf-8
__author__ = 'helen'
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from src.common import log
from config.globalparameter import img_path '''
project:封装页面公用方法
''' class BasePage(object):
def __init__(self, selenium_driver, base_url, page_title):
self.driver = selenium_driver
self.url = base_url
self.title = page_title
self.mylog = log.log() # 打开页面,并校验链接是否加载正确
def _open(self, url, page_title):
try:
self.driver.get(url)
self.driver.maximize_window()
# 通过断言输入的title是否在当前title中
assert page_title in self.driver.title, u'打开页面失败:%s' % url
except:
self.mylog.error(u'未能正确打开页面:'+url) # 重写find_element方法,增加定位元素的健壮性
def find_element(self, *loc):
try:
WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located(loc))
return self.driver.find_element(*loc)
except:
self.mylog.error(u'找不到元素:'+str(loc)) # 重写send_keys方法
def send_keys(self, value, clear=True, *loc):
try:
if clear:
self.find_element(*loc).clear()
self.find_element(*loc).send_keys(value)
except AttributeError:
self.mylog.error(u'输入失败,loc='+str(loc)+u';value='+value) # 截图
def img_screenshot(self, img_name):
try:
self.driver.get_screenshot_as_file(img_path+img_name+'.png')
except:
self.mylog.error(u'截图失败:'+img_name)
6) baidu_page.py
# coding:utf-8
__author__ = 'helen'
from selenium.webdriver.common.by import By
from src.common.Base_Page import BasePage
from selenium.webdriver.common.action_chains import ActionChains class BaiduPage(BasePage):
# 定位器
keywords_loc = (By.ID, 'kw')
submit_loc = (By.ID, 'su')
hao123_loc = (By.NAME, 'tj_trhao123')
more_loc = (By.LINK_TEXT, u'更多产品')
zhidao_loc = (By.NAME,'tj_zhidao') # 打开页面
def open(self):
self._open(self.url, self.title) # 输入关键词
def input_keywords(self, keywords):
self.find_element(*self.keywords_loc).send_keys(keywords) # 点击搜索按钮
def click_submit(self):
self.find_element(*self.submit_loc).click() # 点击hao123链接
def click_hao123(self):
self.find_element(*self.hao123_loc).click() # 鼠标悬停在"更多产品"上
def ActionChains_more(self):
mouse = self.find_element(*self.more_loc)
ActionChains(self.driver).move_to_element(mouse).perform() # 点击“全部产品”
def click_zhidao(self):
self.find_element(*self.zhidao_loc).click()
7) test_baidu.py
# coding:utf-8
__author__ = 'helen'
import unittest
from selenium import webdriver
from src.pages.baidu_page import BaiduPage
from time import sleep
'''
project:百度页面测试
''' class TestBaiduSearch(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.url = 'https://www.baidu.com/'
self.keyword = 'python'
self.baidu_page = BaiduPage(self.driver, self.url, u'百度') def test_baidu_search(self):
u'''百度搜索'''
try:
self.baidu_page.open()
self.baidu_page.input_keywords(self.keyword)
self.baidu_page.click_submit()
sleep(2)
self.assertIn(self.keyword, self.driver.title)
except Exception as e:
self.baidu_page.img_screenshot(u'百度搜索')
raise e def test_baidu_changeto_hao123(self):
u'''从百度首页打开hao123'''
try:
self.baidu_page.open()
self.baidu_page.click_hao123()
self.assertEqual(self.driver.current_url, 'https://www.hao123.com/')
except Exception as e:
self.baidu_page.img_screenshot(u'从百度首页打开hao123')
raise e def test_baidu_more(self):
u'''打开百度知道'''
try:
self.baidu_page.open()
self.baidu_page.ActionChains_more()
self.baidu_page.click_zhidao()
self.assertEqual(self.driver.current_url, 'https://zhidao.baidu.com/')
except Exception as e:
self.baidu_page.img_screenshot(u'打开百度知道')
raise e def tearDown(self):
self.driver.close()
8) sogou_page.py
# coding:utf-8
__author__ = 'helen'
from selenium.webdriver.common.by import By
from src.common.Base_Page import BasePage
'''
project:sogo页面元素管理
'''
class sogou_page(BasePage):
# 定位
keyword_loc = (By.ID, 'query')
sumit_loc = (By.ID, 'stb') def open(self):
self._open(self.url,self.title) # 输入关键词
def input_keyword(self, value):
self.find_element(*self.keyword_loc).send_keys(value) # 点击搜索
def click_sumit(self):
self.find_element(*self.sumit_loc).click()
9) test_sogou.py
# coding:utf-8
__author__ = 'helen'
import unittest
from selenium import webdriver
from src.pages.sogou_page import sogou_page
from src.common.log import log
from src.common import excel_data
'''sogou页面测试
''' class test_sogou(unittest.TestCase):
def setUp(self):
self.mylog = log()
self.driver = webdriver.Firefox()
self.url = 'https://www.sogou.com/'
self.sogou_page = sogou_page(self.driver,self.url,u'搜狗')
self.excel = excel_data.excel() def test_search(self):
u'''搜狗搜索:excel数据驱动'''
keyword_list = self.excel.get_list('sogou_search')
for i in range(0, len(keyword_list)):
keyword = keyword_list[i]["keyword"]
try:
self.sogou_page.open()
self.sogou_page.input_keyword(keyword)
self.sogou_page.click_sumit()
# 因为assert对比是的str所以要判断keyword类型如何不是str, 就要进行转换
if type(keyword)!=str:
keyword = str(keyword)
self.assertIn(keyword,self.driver.title)
except Exception as e:
self.mylog.error('error for search keyword:'+str(keyword))
self.sogou_page.img_screenshot(u'搜狗搜索')
raise e def tearDown(self):
self.driver.close()
if __name__=='__main__':
unittest.main()
10) runtest.py
# coding:utf-8
__author__ = 'helen'
import unittest,time,HTMLTestRunner
from config.globalparameter import test_case_path,report_name
from src.common import send_email
'''
构建测试套件,并执行测试
''' # 构建测试集,包含src/test_case目录下的所有以test开头的.py文件
suite = unittest.defaultTestLoader.discover(start_dir=test_case_path,pattern='test*.py') # 执行测试
if __name__=="__main__":
report = report_name+"Report.html"
fb = open(report,'wb')
runner = HTMLTestRunner.HTMLTestRunner(
stream=fb,
title=u'自动化测试报告',
description=u'项目描述。………'
)
runner.run(suite)
fb.close()
# 发送邮件
time.sleep(10) # 设置睡眠时间,等待测试报告生成完毕(这里被坑了==)
email = send_email.send_email()
email.sendReport()
selenium实例:unittest框架+PO开发模式的更多相关文章
- pycharm中脚本执行的3种模式(unittest框架、pytest框架、普通模式)
背景知识,某次使用HTMLTestRunner的时候,发现一直都无法导出报告,后来查询资料发现了一些坑,现在整理一下来龙去脉. 一:pycharm默认的是pytest框架去执行unittest框架的测 ...
- .net开发笔记(十三) Winform常用开发模式第一篇
上一篇博客最后我提到“异步编程模型”(APM),之后本来打算整理一下这方面的材料然后总结一下写篇文章与诸位分享,后来在整理的过程中不断的延伸不断地扩展,发现完全偏离了“异步编程”这个概念,前前后后所有 ...
- javaweb的开发模式
SUN公司推出JSP技术后,同时也推荐了两种web应用程序的开发模式,一种是JSP+JavaBean模式,一种是Servlet+JSP+JavaBean模式. 一.JSP+JavaBean开发模式 1 ...
- Winform常用开发模式第一篇
Winform常用开发模式第一篇 上一篇博客最后我提到“异步编程模型”(APM),之后本来打算整理一下这方面的材料然后总结一下写篇文章与诸位分享,后来在整理的过程中不断的延伸不断地扩展,发现完全偏离了 ...
- UI开发模式对比:JSP、Android、Flex
前一篇文章分析了Java平台下不同类型WEB框架对开发模式的影响,多数Java领域的WEB框架都是聚焦于服务端MVC的实现,这些框架对View的支持,通常是基于标准的JSP或类似JSP的模板技术如Fr ...
- Python+Selenium+Unittest实现PO模式web自动化框架(6)
1.TestCases目录下的模块 TestCases目录下是存放测试用例的目录. TestCases目录下的测试用例采用unittest框架来构建. 例如:登录功能的测试用例.(test_1_log ...
- [转]Tangram框架应用开发的一般模式
//转的,怕想百度博客一样搬家,赶紧先复制下来. 框架其实就是一种开发模式,用tangram框架开发应用程序意味着选择一种面向接口.模块化的开发方式.这和传统的Delphi应用程序开发方式有一定区别, ...
- IOS 与ANDROID框架及应用开发模式对照一
IOS 和ANDROID操作系统都是眼下流行的移动操作系统,被移动终端和智能设备大量採用,两者都採用了先进的软件技术进行设计,为了方便应用开发两者都採用了先进的设计模式. 两者在框架设计上都採用了什么 ...
- IOS 与ANDROID框架及应用开发模式对比一
IOS 和ANDROID操作系统都是目前流行的移动操作系统,被移动终端和智能设备大量采用,两者都采用了先进的软件技术进行设计,为了方便应用开发两者都采用了先进的设计模式.两者在框架设计上都采用了什么技 ...
随机推荐
- React Native填坑之旅 -- 使用iOS原生视图(高德地图)
在开发React Native的App的时候,你会遇到很多情况是原生的视图组件已经开发好了的.有的是系统的SDK提供的,有的是第三方试图组件,总之你的APP可以直接使用的原生视图是很多的.React ...
- LINQ中,Single()、SingleOrDefault()的解析、示例
LINQ一般查询到的结果是IEnumerable<T>集合类型,想要从中取出单一的元素,可以使用Single.First.Last.ElementAt等方法,以及它们带有OrDefault ...
- 高精度模板 Luogu P1932 A+B & A-B & A*B & A/B Problem
P1932 A+B & A-B & A*B & A/B Problem 题目背景 这个题目很新颖吧!!! 题目描述 求A.B的和差积商余! 输入输出格式 输入格式: 两个数两行 ...
- 关于java socket
1. 关于new Socket()中参数的理解 Server端: 调用ServerSocket serverSocket = new ServerSocket(1287,2);后Server端打开了指 ...
- RMI原理及简单示例
分布式对象 在学习 RMI 之前,先来分布式对象(Distributed Object):分布式对象是指一个对象可以被远程系统所调用.对于 Java 而言,即对象不仅可以被同一虚拟机中的其他客户程序( ...
- ACM 重建二叉树
重建二叉树 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 题目很简单,给你一棵二叉树的后序和中序序列,求出它的前序序列(So easy!). 输入 输入有多组数 ...
- 1643: [Usaco2007 Oct]Bessie's Secret Pasture 贝茜的秘密草坪
1643: [Usaco2007 Oct]Bessie's Secret Pasture 贝茜的秘密草坪 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 2 ...
- 【HLA】初识HLA/RTI
本文主要对近期所翻阅的一些论文及资料进行的概要性整理,后续会有更多的关于HLA的研究细节发布,基于博客园的知识共享平台,以期共同进步! 一.引言 仿真的历史由来已久,在系统研制过程中,基于建模及仿真技 ...
- Golang版protobuf编译
官方网址: https://developers.google.com/protocol-buffers/ (需要FQ) 代码仓库: https://github.com/google/protobu ...
- 最大化最小值 Aggressive cows
Aggressive cows http://poj.org/problem?id=2456 N间小屋,M头牛,使得牛跟牛之间的距离最远,以防止牛打架. 2<=N<=100000 2< ...