1、日志模块
import logging
from logging.handlers import RotatingFileHandler
import time
from Common import dir_config
"""
asctime:字符串形式的当前时间
levelname:文本形式的日志级别
filename:调用函数所在模块的文件名称
funcName:日志输出的函数名
lineno:函数语句执行所在代码行
message:用户输出信息
"""
log_fmt = " %(asctime)s %(levelname)s %(filename)s %(funcName)s [line:%(lineno)d] %(message)s "
"""
%a:本地星期的简称
%d:一个月中的第几天
%b:本地月份的简称
%Y:年份的完整表达形式
%H:24小时制的小时
%M:分钟
%S:秒数
"""
date_fmt = " %a, %d %b %Y %H:%M:%S "
cur_time = time.strftime("%Y-%m-%d %H%M", time.localtime())
handler_1 = logging.StreamHandler()
handler_2 = RotatingFileHandler(
dir_config.logs_path + "/Web_Autotest_{0}.log".format(cur_time),
backupCount=20,
encoding='utf-8'
)
logging.basicConfig(
format=log_fmt,
datefmt=date_fmt,
level=logging.INFO,
handlers=[handler_1, handler_2]
)
2、文件存储
import os
base_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
logs_path = os.path.join(base_path, "Outputs\logs")
reports_path = os.path.join(base_path, "Outputs\\reports")
screenshots_path = os.path.join(base_path, "Outputs\screenshots")
Testcases_path = os.path.join(base_path, "Testcases")
Testdatas_path = os.path.join(base_path, "Testdatas")
3、Common封装
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
import calendar as cal
import time
import datetime
import win32api
import win32con
import pyperclip
from Common import logger_fun
from Common.dir_config import screenshots_path
class BasePage:
"""
包含了PageObjects当中,用到所有的selenium底层方法
还可以包含通用的一些元素操作,如alert,iframe,windows...
实现日志记录、实现失败截图
"""
def __init__(self, driver: WebDriver):
self.driver = driver
def wait_elevisible(self, loc, timeout=120, frequency=0.5, doc="" ):
"""
:param loc:要等待的元素定位(必传)
:param timeout:超时时间
:param frequency:轮询周期
:param doc:备注
:return:
"""
start_time = time.time()
try:
WebDriverWait(self.driver, timeout, frequency).until(EC.visibility_of_element_located(loc))
except:
logger_fun.logging.exception("等待{}元素可见超时".format(loc))
self.do_save_screenshot(doc)
raise
else:
end_time = time.time()
duration = end_time - start_time
logger_fun.logging.info("等待{}元素可见,耗时{}".format(loc, duration))
def get_element(self, loc, doc=""):
"""
:param loc:要查找元素的元素定位(必传)
:param doc:备注
:return:
"""
try:
ele = self.driver.find_element(*loc)
except:
logger_fun.logging.exception("查找{}元素存在,失败!".format(loc))
self.do_save_screenshot(doc)
raise
else:
logger_fun.logging.info("查找{}的元素{}成功。".format(doc, loc))
return ele
def do_save_screenshot(self, doc=""):
"""
:param doc:备注
:return:
"""
cur_time = datetime.datetime.strftime(datetime.datetime.now(), '%Y%m%d%H%M%S')
file = screenshots_path+"/{}_{}.png".format(doc, cur_time)
try:
self.driver.save_screenshot(file)
except:
logger_fun.logging.exception("网页截图操作失败")
else:
logger_fun.logging.info("截图成功,存储路径为:{0}".format(file))
def is_element_present(self, loc, timeout=10, frequency=0.5, doc=""):
"""
:param loc:要查找元素的元素定位(必传)
:param timeout:超时时间
:param frequency:轮询周期(多久查看一下元素是否在页面中出现)
:param doc:备注
:return:
"""
time.sleep(0.5)
self.wait_elevisible(loc, timeout, frequency, doc)
ele = self.get_element(loc, doc)
try:
ele.is_displayed()
except:
logger_fun.logging.exception("{}元素不可见".format(loc))
self.do_save_screenshot(doc)
raise
else:
logger_fun.logging.info("{}元素可见".format(loc))
def input_text(self, loc, value, timeout=60, frequency=0.5, doc=""):
"""
:param loc:文本输入框的输入框元素定位(必传)
:param value:输入的值(必传)
:param timeout:超时时间
:param frequency:轮循周期
:param doc:备注
:return:
"""
self.wait_elevisible(loc, timeout, frequency, doc)
ele = self.get_element(loc, doc)
try:
ele.send_keys(value)
except:
logger_fun.logging.exception("向{}元素输入{}失败".format(loc, value))
self.do_save_screenshot(doc)
raise
else:
logger_fun.logging.info("向{}元素输入{}成功".format(loc, value))
def clear_text(self, loc, timeout=60, frequency=0.5, doc=""):
"""
:param loc:要清空文本输入框的输入框元素定位(必传)
:param timeout:超时时间
:param frequency:轮询周期
:param doc:备注
:return:
"""
self.wait_elevisible(loc, timeout, frequency, doc)
ele = self.get_element(loc, doc)
try:
ele.clear()
except:
logger_fun.logging.exception("清除{}内容失败".format(loc))
self.do_save_screenshot(doc)
raise
else:
logger_fun.logging.info("清除{}内容成功".format(loc))
def click(self, loc: object, timeout: object = 60, frequency: object = 0.5, doc: object = "") -> object:
"""
:param loc:要点击元素的元素定位(必传)
:param timeout:超时时间
:param frequency:轮询周期
:param doc:备注
:return:
"""
time.sleep(0.5)
self.wait_elevisible(loc, timeout, frequency, doc)
ele = self.get_element(loc, doc)
try:
ele.click()
except:
logger_fun.logging.exception("向{}元素点击失败".format(loc))
self.do_save_screenshot(doc)
raise
else:
logger_fun.logging.info("向{}元素点击成功".format(loc))
def get_element_text(self, loc, timeout=60, frequency=0.5, doc=""):
"""
:param loc:要获取元素文本值的元素定位(必传)
:param timeout:超时时间
:param frequency:轮循周期
:param doc:备注
:return:
"""
self.wait_elevisible(loc, timeout, frequency, doc)
ele = self.get_element(loc, doc)
try:
text = ele.text
except:
logger_fun.logging.exception("获取{}元素文本值失败".format(loc))
self.do_save_screenshot(doc)
raise
else:
logger_fun.logging.info("获取{}元素文本值成功".format(loc))
return text
def get_element_attribute(self, loc, attr, timeout=60, frequency=0.5, doc=""):
"""
:param loc:要获取元素属性值的元素定位(必传)
:param attr:要获取元素属性值的元素属性名(必传)
:param timeout:超时时间
:param frequency:轮循周期
:param doc:备注
:return:
"""
self.wait_elevisible(loc, timeout, frequency, doc)
ele = self.get_element(loc, doc)
try:
value = ele.get_attribute(attr)
except:
logger_fun.logging.exception("获取{}元素属性值失败".format(loc))
self.do_save_screenshot(doc)
raise
else:
logger_fun.logging.info("获取{}元素属性值成功".format(loc))
return value
def get_list_length(self, loc, timeout=60, frequency=0.5, doc=""):
"""
:param loc:要获取元素数量的元素定位
:param timeout:超时时间
:param frequency:轮循周期
:param doc:备注
:return:
"""
self.wait_elevisible(loc, timeout, frequency, doc)
ele = self.get_elements(loc, doc)
try:
value = len(ele)
except:
logger_fun.logging.exception("获取{}元素属性值失败".format(loc))
self.do_save_screenshot(doc)
return 0
else:
logger_fun.logging.info("获取{}元素属性值成功".format(loc))
return value
def get_list_single_column(self, table_tbody, j, doc=''):
"""
:param table_tbody: 表格定位路径
:param j:获取第几列元素
:param doc:备注信息
:return:将列内容返回至列表中
"""
element = self.driver.find_element_by_xpath(table_tbody)
table_tr_list = element.find_elements_by_tag_name("tr")
time.sleep(1)
table_list = []
total_numbers = len(table_tr_list)
if total_numbers >= 1:
for i in range(1, total_numbers + 1):
table_td_list = self.driver.find_elements_by_xpath(table_tbody + '//tr[' + str(i) + ']//td[' + str(j) + ']')[0]
table_td_list1 = table_td_list.get_attribute('textContent')
table_list.append(table_td_list1)
new_table_list = [x.strip() for x in table_list if x.strip() != '']
return new_table_list
else:
ret_info = "列表数据为空"
return ret_info
def get_list_all_datas(self, table_tbody):
time.sleep(1)
list_1 = []
element = self.driver.find_element_by_xpath(table_tbody)
table_tr_list = element.find_elements_by_tag_name("tr")
for tr in table_tr_list:
list_2 = (tr.text).split()
list_1.append(list_2)
if list_1 != []:
return list_1
else:
ret_info = "列表数据为空"
return ret_info
def switch_window(self, doc=""):
"""
:param doc: 备注
:return:
"""
try:
windows = self.driver.window_handles
self.driver.switch_to.window(windows[-1])
except:
logger_fun.logging.exception("切换窗口失败")
self.do_save_screenshot(doc)
raise
else:
logger_fun.logging.info("切换窗口成功")
def get_date(self):
return time.strftime("%Y-%m-%d", time.localtime(time.time()))
def get_default_value(self, loc, timeout=60, frequency=0.5, doc=""):
"""
:param loc:获取元素的元素定位(必传)
:param timeout: 超时时间
:param frequency:轮循周期
:param doc:备注
:return:
"""
self.wait_elevisible(loc, timeout, frequency, doc)
ele = self.get_element(loc, doc)
try:
default_value = ele.get_attribute('value')
except:
logger_fun.logging.exception("获取{}元素文本值失败".format(loc))
self.do_save_screenshot(doc)
raise
else:
logger_fun.logging.info("获取{}元素文本值成功".format(loc))
return default_value
def switch_iframe_by_id(self, id, doc=""):
self.driver.switch_to.frame(self.driver.find_element_by_id(id))
def switch_iframe_by_xpath(self, xpath, doc=""):
self.driver.switch_to.frame(self.driver.find_element_by_xpath(xpath))
def switch_iframe_by_element(self, element, doc=""):
self.driver.switch_to.frame(self.driver.find_element(*element))
def input_text_uploadfile(self, loc, value, timeout=60, frequency=0.5, doc=""):
"""
:param loc:要上传文件的上传按钮元素定位(必传)
:param value:要上传的文件名(必传:绝对路径)
:param timeout:超时时间
:param frequency:轮循周期
:param doc:备注
:return:
"""
self.wait_elevisible(loc, timeout, frequency, doc)
ele = self.get_element(loc, doc)
try:
ele.send_keys(value)
except:
logger_fun.logging.exception("向{}元素输入{}失败".format(loc, value))
self.do_save_screenshot(doc)
raise
else:
logger_fun.logging.info("向{}元素输入{}成功".format(loc, value))
def isnot_input_uploadfile(self, eleLoc, filePath, doc=''):
"""
使用python的win32api,win32con模拟按键输入,实现文件上传操作
:param eleLoc: 页面中的上传文件按钮
:param filePath: 要上传的文件地址(绝对路径)
:param doc: 备注信息
:return:
"""
try:
pyperclip.copy(filePath)
self.click(eleLoc)
time.sleep(3)
win32api.keybd_event(17, 0, 0, 0)
win32api.keybd_event(86, 0, 0, 0)
win32api.keybd_event(86, 0, win32con.KEYEVENTF_KEYUP, 0)
win32api.keybd_event(17, 0, win32con.KEYEVENTF_KEYUP, 0)
time.sleep(1)
win32api.keybd_event(13, 0, 0, 0)
win32api.keybd_event(13, 0, win32con.KEYEVENTF_KEYUP, 0)
except:
time.sleep(1)
logger_fun.logging.info("向{}元素上传文件失败".format(eleLoc))
self.do_save_screenshot(eleLoc)
raise
else:
time.sleep(1)
logger_fun.logging.info("向{}元素上传文件成功".format(eleLoc))
def move_to_element(self, loc, Index=1, timeout=120, frequency=0.5, doc=""):
"""
:param loc: 要移动到某个元素的元素定位(必传)
:param Index: 元素下标
:param timeout: 超时时间
:param frequency: 轮循周期
:param doc: 备注
:return:
"""
ac = ActionChains(self.driver)
ele = self.get_elements(loc, doc)[Index]
ac.move_to_element(ele)
ac.perform()
4、main函数
from Common.dir_config import logs_path, screenshots_path, Testcases_path, reports_path
from BeautifulReport import BeautifulReport
import unittest
from Common.delete_log import DeleteLogFile as DF
"""Windows系统"""
Del_log = DF(r"{}".format(logs_path), r"{}".format(screenshots_path))
Del_log.delete_file()
if __name__ == '__main__':
suite_tests = unittest.defaultTestLoader.discover(r"{}".format(Testcases_path))
BeautifulReport(suite_tests).report(
filename='Auto_Testing_01自动化测试报告',
description='Auto_Testing_01自动化测试报告',
report_dir=r'{}'.format(reports_path)
)
5、删除日志、测试报告
import os
class DeleteLogFile:
def __init__(self, path_1, path_2):
self.path_1 = path_1
self.path_2 = path_2
def delete_file(self):
for path in [self.path_1, self.path_2]:
all_log_files = os.listdir(path)
all_log_files.sort()
for num in range(len(all_log_files)):
os.remove(os.path.join(path,all_log_files[num]))
6、测试用例
import unittest
from selenium import webdriver
import time
class TestLogin(unittest.TestCase):
def setUp(self):
executable_path = r"G:\BaiduNetdiskDownload\chromedriver.exe"
self.driver = webdriver.Chrome(executable_path)
self.driver.get(GD.login_url_mainframe)
self.driver.maximize_window()
def tearDown(self):
self.driver.quit()