Web UI自动化测试之日志收集篇
优采云 发布时间: 2022-05-11 11:05Web UI自动化测试之日志收集篇
本文大纲截图:
1、日志介绍
日志: 用于记录系统运行时的信息,对一个事件的记录,也称为Log。
日志作用:
日志级别:
日志级别:指日志信息的优先级、重要性或者严重程度。
常见的日志级别: DEBUG、INFO、WARNING、ERROR、CRITICAL
import logging<br /><br /><br />logging.debug("这是一条调试信息")<br />logging.info("这是一条普通信息")<br />logging.warning("这是一条警告信息")<br />logging.error("这是一条错误信息")<br />logging.critical("这是一条严重错误信息")<br />
说明:
2、日志用法2.1 基本用法
设置日志级别:
设置日志格式:
代码示例:
import logging<br /><br />fmt = '%(asctime)s %(levelname)s [%(name)s] [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s'<br />logging.basicConfig(level=logging.INFO, format=fmt)<br /><br />logging.debug("调试")<br />logging.info("信息")<br />logging.warning("警告")<br />logging.error("错误")<br />
将日志信息输出到文件中
import logging<br /><br />fmt = '%(asctime)s %(levelname)s [%(name)s] [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s'<br />logging.basicConfig(filename="a.log", level=logging.INFO, format=fmt)<br /><br />logging.debug("调试")<br />logging.info("信息")<br />logging.warning("警告")<br />logging.error("错误")<br />
2.2 高级用法
logging日志模块四大组件: Logger、Handler、Formatter、Filter
组件关系:
Logger类:
Logger常用的方法:
设置日志级别:logger.setLevel(),设置日志器将会处理的日志消息的最低严重级别
添加handler对象:logger.addHandler(),为该logger对象添加一个handler对象
添加filter对象:logger.addFilter(),为该logger对象添加一个filter对象
Handler类:
Handler常用的方法:
Formatter类:
将日志信息同时输出到控制台和文件中:
定义日志格式:
# 设置日志格式<br />fmt = '%(asctime)s %(levelname)s [%(name)s] [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s'<br /># 创建格式化器对象<br />formatter = logging.Formatter(fmt)<br />
logger = logging.getLogger()<br />sh = logging.StreamHandler()<br />sh.setFormatter(formatter)<br />logger.addHandler(sh)<br />
fh = logging.FileHandler("./b.log")<br />fh.setFormatter(formatter)<br />logger.addHandler(fh)<br />
每日生成一个日志文件:
fh = logging.handlers.TimedRotatingFileHandler(filename, when='h', interval=1, backupCount=0)<br /> # 将日志信息记录到文件中,以特定的时间间隔切换日志文件。<br /> # filename: 日志文件名<br /> # when: 时间单位,可选参数<br /> # S - Seconds<br /> # M - Minutes<br /> # H - Hours<br /> # D - Days<br /> # midnight - roll over at midnight<br /> # W{0-6} - roll over on a certain day; 0 - Monday<br /> # interval: 时间间隔<br /> # backupCount: 日志文件备份数量。<br /> # 如果backupCount大于0,那么当生成新的日志文件时,将只保留backupCount个文件,删除最老的文件。<br />
import logging.handlers<br /><br /><br />logger = logging.getLogger()<br />logger.setLevel(logging.DEBUG)<br /><br /># 日志格式<br />fmt = "%(asctime)s %(levelname)s [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s"<br />formatter = logging.Formatter(fmt)<br /><br /># 输出到文件,每日一个文件<br />fh = logging.handlers.TimedRotatingFileHandler("./a.log", when='MIDNIGHT', interval=1, backupCount=3)<br />fh.setFormatter(formatter)<br />fh.setLevel(logging.INFO)<br />logger.addHandler(fh)<br />
日志封装成工具(tools):
# 导包<br />import logging.handlers<br /><br /><br /># 定义日志器方法 ,封装日志<br />def get_logger():<br /> # 获取 日志器logger,并设置名称admin<br /> logger = logging.getLogger("admin")<br /> # 设置日志级别为info<br /> logger.setLevel(logging.INFO)<br /> # 获取 控制台处理器<br /> sh = logging.StreamHandler()<br /> # 获取 文件处理器,根据时间分割<br /> th = logging.handlers.TimedRotatingFileHandler(filename="../log/logger.log", when="S", interval=1, backupCount=2, encoding="utf-8")<br /> # 设置 文件处理器 日志级别<br /> th.setLevel(logging.ERROR)<br /> # 获取 格式器<br /> fmt = "%(asctime)s %(levelname)s [%(name)s] [%(filename)s (%(funcName)s %(lineno)d)] - %(message)s"<br /> fm = logging.Formatter(fmt)<br /> # 将 格式器 添加到 处理器中<br /> sh.setFormatter(fm)<br /> th.setFormatter(fm)<br /> # 将 处理器 添加到 日志器中<br /> logger.addHandler(sh)<br /> logger.addHandler(th)<br /> # 返回 logger<br /> return logger<br /><br /><br />if __name__ == '__main__':<br /> logger = get_logger()<br /> # 日志器应用<br /> logger.info("这是info信息")<br /> logger.warning("这是warning信息")<br /> logger.error("这是error信息")<br />
3、日志应用
日志应用:PO模式中,在base操作层、page对象层、scripts业务层都可添加日志,以及将日志用单例模式封装成工具类放在tools文件夹中。
import time<br />from time import sleep<br />from selenium.webdriver.support.wait import WebDriverWait<br />from day11_tpshop import page<br />from day11_tpshop.base.get_logger import GetLogger<br /><br /># 获取log日志器<br />log = GetLogger().get_logger()<br /><br /><br />class Base:<br /> def __init__(self, driver):<br /> log.info("[base:]正在获取初始化driver对象:{}".format(driver))<br /> self.driver = driver<br /><br /> # 查找元素方法 封装<br /> def base_find(self, loc, timeout=30, poll=0.5):<br /> log.info("[base]:正在定位:{}元素,默认定位超时时间为:{}".format(loc, timeout))<br /> # 使用显式等待 查找元素<br /> return WebDriverWait(self.driver,<br /> timeout=timeout,<br /> poll_frequency=poll).until(lambda x: x.find_element(*loc))<br /><br /> # 点击元素方法 封装<br /> def base_click(self, loc):<br /> log.info("[base]:正在对:{}元素执行点击事件".format(loc))<br /> self.base_find(loc).click()<br /><br /> # 输入元素方法 封装<br /> def base_input(self, loc, value):<br /> log.info("[base]:正在获取:{}元素".format(loc))<br /> # 获取元素<br /> el = self.base_find(loc)<br /> log.info("[base]:正在对:{}元素执行清空操作".format(loc))<br /> # 输入前 清空<br /> el.clear()<br /> log.info("[base]:正在给{}元素输入内容:{}".format(loc, value))<br /> # 输入<br /> el.send_keys(value)<br /><br /> # 获取文本信息方法 封装<br /> def base_get_text(self, loc):<br /> log.info("[base]:正在获取{}元素文本值".format(loc))<br /> return self.base_find(loc).text<br /><br /> # 截图方法 封装<br /> def base_get_img(self):<br /> log.info("[base]:断言出错,调用截图")<br /> self.driver.get_screenshot_as_file("../image/{}.png".format(time.strftime("%Y_%m_%d %H_%M_%S")))<br /><br /> # 判断元素是否存在方法 封装<br /> def base_elememt_is_exist(self, loc):<br /> try:<br /> self.base_find(loc, timeout=2)<br /> log.info("[base]:{}元素查找成功,存在页面".format(loc))<br /> return True # 代表元素存在<br /> except:<br /> log.info("[base]:{}元素查找失败,不存在当前页面".format(loc))<br /> return False # 代表元素不存在<br /><br /> # 回到首页(购物车、下订单、支付)都需要用到此方法<br /> def base_index(self):<br /> # 暂停2秒<br /> sleep(2)<br /> log.info("[base]:正在打开首页")<br /> self.driver.get(page.URL)<br /><br /> # 切到frame表单方法 以元素属性切换<br /> def base_switch_frame(self, element):<br /> log.info("[base]:正在切换到frame表单")<br /> self.driver.switch_to.frame(element)<br /><br /> # 回到默认目录方法<br /> def base_default_content(self):<br /> log.info("[base]:正在返回默认目录")<br /> self.driver.switch_to.default_content()<br /><br /> # 切换窗口方法<br /> def base_switch_to_window(self, title):<br /> log.info("正在执行切换title值为:{}窗口".format(title))<br /> self.base_get_title_handle(title)<br /> # self.driver.switch_to.window(self.base_get_title_handle(title))<br /><br /> # 获取指定title页面的handle方法<br /> def base_get_title_handle(self, title):<br /> # 获取当前页面所有的handles<br /> handles = self.driver.window_handles<br /> # 遍历handle<br /> for handle in handles:<br /> log.info("正在遍历handles:{}-->{}".format(handle, handles))<br /> # 切换 handle<br /> self.driver.switch_to.window(handle)<br /> log.info("切换:{}窗口".format(handle))<br /> # 获取当前页面title 并判断 是否等于 指定参数title<br /> log.info("条件成立!返回当前handle{}".format(handle))<br /> if self.driver.title == title:<br /> # 返回 handle<br /> return handle<br />
from day11_tpshop import page<br />from day11_tpshop.base.base import Base<br />from day11_tpshop.base.get_logger import GetLogger<br /><br /># 获取log日志器<br />log = GetLogger().get_logger()<br /><br /><br />class PageLogin(Base):<br /> # 点击 登录链接<br /> def page_click_login_link(self):<br /> log.info("[page_login]:执行{}元素点击链接操作".format(page.login_link))<br /> self.base_click(page.login_link)<br /><br /> # 输入用户名<br /> def page_input_username(self, username):<br /> log.info("[page_login]:对{}元素 输入用户名{}操作".format(page.login_username, username))<br /> self.base_input(page.login_username, username)<br /><br /> # 输入密码<br /> def page_input_pwd(self, pwd):<br /> log.info("[page_login]:对{}元素 输入密码{}操作".format(page.login_pwd, pwd))<br /> self.base_input(page.login_pwd, pwd)<br /><br /> # 输入验证码<br /> def page_input_verify_code(self, verify_code):<br /> log.info("[page_login]:对{}元素 输入验证码{}操作".format(page.login_verify_code, verify_code))<br /> self.base_input(page.login_verify_code, verify_code)<br /><br /> # 点击 登录<br /> def page_click_login_btn(self):<br /> log.info("[page_login]:执行{}元素点击操作".format(page.login_btn))<br /> self.base_click(page.login_btn)<br /><br /> # 获取 错误提示信息<br /> def page_get_err_info(self):<br /> return self.base_get_text(page.login_err_info)<br /><br /> # 点击 错误提示框 确定按钮<br /> def page_click_error_alert(self):<br /> log.info("[page_login]:执行{}元素点击操作".format(page.login_err_ok_btn))<br /> self.base_click(page.login_err_ok_btn)<br /><br /> # 判断是否登录成功<br /> def page_if_login_success(self):<br /> # 注意 一定要将找元素的结果返回,True:存在<br /> return self.base_elememt_is_exist(page.login_logout_link)<br /><br /> # 点击 安全退出<br /> def page_click_logout_link(self):<br /> self.base_click(page.login_logout_link)<br /><br /> # 判断是否退出成功<br /> def page_if_logout_success(self):<br /> return self.base_elememt_is_exist(page.login_link)<br /><br /> # 组合业务方法 登录业务直接调用<br /> def page_login(self, username, pwd, verify_code):<br /> log.info("[page_login]:正在执行登录操作,用户名:{},密码:{},验证码:{}".format(username, pwd, verify_code))<br /> self.page_input_username(username)<br /> self.page_input_pwd(pwd)<br /> self.page_input_verify_code(verify_code)<br /> self.page_click_login_btn()<br /><br /> # 组合登录业务方法 给(购物车模块、订单模块、支付模块)依赖登录使用<br /> def page_login_success(self, username="13800001111", pwd="123456", verify_code="8888"):<br /> # 点击登录链接<br /> self.page_click_login_link()<br /> log.info("[page_login]:正在执行登录操作,用户名:{},密码:{},验证码:{}".format(username, pwd, verify_code))<br /> self.page_input_username(username)<br /> self.page_input_pwd(pwd)<br /> self.page_input_verify_code(verify_code)<br /> self.page_click_login_btn()<br />
import unittest<br />from day11_TPshop项目.base.get_driver import GetDriver<br />from day11_TPshop项目.base.get_logger import GetLogger<br />from day11_TPshop项目.page.page_login import PageLogin<br />from day11_TPshop项目.tools.read_txt import read_txt<br />from parameterized import parameterized<br /><br /># 获取log日志器<br />log = GetLogger().get_logger()<br /><br /><br />def get_data():<br /> arrs = []<br /> for data in read_txt("login.txt"):<br /> arrs.append(tuple(data.strip().split(",")))<br /> return arrs[1:]<br /><br /><br /># 新建 登录测试类 并 继承 unittest.TestCase<br />class TestLogin(unittest.TestCase):<br /> # 新建 setUpClass<br /> @classmethod<br /> def setUpClass(cls) -> None:<br /> try:<br /> # 实例化 并获取 driver<br /> cls.driver = GetDriver.get_driver()<br /> # 实例化 PageLogin()<br /> cls.login = PageLogin(cls.driver)<br /> # 点击登录链接<br /> cls.login.page_click_login_link()<br /> except Exception as e:<br /> # 截图<br /> cls.login.base_get_img()<br /> # 日志<br /> log.error("错误:{}".format(e))<br /><br /> # 新建 tearDownClass<br /> @classmethod<br /> def tearDownClass(cls) -> None:<br /> # 关闭driver驱动对象<br /> GetDriver.quit_driver()<br /><br /> # 新建 登录测试方法<br /> @parameterized.expand(get_data())<br /> def test_login(self, username, pwd, verify_code, expect_result, status):<br /> try:<br /> # 调用 登录业务方法<br /> self.login.page_login(username, pwd, verify_code)<br /><br /> # 判断是否为正向<br /> if status == "true":<br /> # 断言是否登录成功<br /> try:<br /> self.assertTrue(self.login.page_if_login_success())<br /> except Exception as e:<br /> # 截图<br /> self.login.base_get_img()<br /> # 日志<br /> log.error("出错了:{}".format(e))<br /> # 点击 安全退出<br /> self.login.page_click_logout_link()<br /> # 点击 登录链接<br /> self.login.page_click_login_link()<br /> # 逆向用例<br /> else:<br /> # 获取错误提示信息<br /> msg = self.login.page_get_err_info()<br /> print("msg:", msg)<br /> try:<br /> self.assertEqual(msg, expect_result)<br /> except Exception as e:<br /> # 截图<br /> self.login.base_get_img()<br /> # 日志<br /> log.error("出错了:{}".format(e))<br /> # 点击错误提示框 确定按钮<br /> self.login.page_click_error_alert()<br /> except Exception as e:<br /> # 截图<br /> self.login.base_get_img()<br /> # 日志<br /> log.error("出错了:{}".format(e))<br />
import logging.handlers<br />import time<br /><br /><br />class GetLogger:<br /> logger = None<br /><br /> # 获取logger<br /> @classmethod<br /> def get_logger(cls):<br /> if cls.logger is None:<br /> # 获取 logger 日志器 并设置名称为“admin”<br /> cls.logger = logging.getLogger("admin")<br /> # 设置日志级别<br /> cls.logger.setLevel(logging.INFO)<br /> # 获取 控制台处理器<br /> sh = logging.StreamHandler()<br /> # 获取 文件处理器 根据时间分割<br /> th = logging.handlers.TimedRotatingFileHandler(<br /> filename="../log/{}.log".format(time.strftime("%Y_%m_%d %H_%M_%S")),<br /> when="S",<br /> interval=1,<br /> backupCount=3,<br /> encoding="utf-8")<br /> # 设置 文件处理器 日志级别<br /> th.setLevel(logging.ERROR)<br /> # 获取 格式器<br /> fmt = "%(asctime)s %(levelname)s [%(name)s] [%(filename)s %(funcName)s %(lineno)d] - %(message)s"<br /> fm = logging.Formatter(fmt)<br /> # 将 格式器 添加到 处理器<br /> sh.setFormatter(fm)<br /> th.setFormatter(fm)<br /> # 将 处理器 添加到 日志器<br /> cls.logger.addHandler(sh)<br /> cls.logger.addHandler(th)<br /> # 返回日志器<br /> return cls.logger<br /><br /><br />if __name__ == '__main__':<br /> logger = GetLogger.get_logger()<br /> # 日志器应用<br /> logger.info("这是info日志信息")<br /> logger.debug("这是debug日志信息")<br /> logger.warning("这是warning日志信息")<br /> logger.error("这是error日志信息")<br />