1、测试场景
给登录今日头条app的操作添加日志采集。
2、简单配置代码示例
import logging
from appium import webdriver
logging.basicConfig(filename='./testLog.log', level=logging.INFO,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')
def android_driver():
desired_caps = {
"platformName": "Android",
"platformVersion": "10",
"deviceName": "PCT_AL10",
"appPackage": "com.ss.android.article.news",
"appActivity": ".activity.MainActivity",
"unicodeKeyboard": True,
"resetKeyboard": True,
"noReset": True,
}
logging.info("启动今日头条APP...")
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
return driver
def login_opera(driver):
'''登录今日头条操作'''
logging.info("开始登陆今日头条APP...")
try:
driver.find_element_by_id("com.ss.android.article.news:id/cji").click() # 点击【我知道了】
driver.find_element_by_id("android:id/button1").click() # 点击权限管理-确定按钮
driver.find_element_by_xpath("//android.widget.TabWidget/android.widget.RelativeLayout[@index=3]").click() # 点击未登录
driver.find_element_by_id("com.ss.android.article.news:id/a10").click() # 未登录页点击登录按钮
driver.find_element_by_id("com.ss.android.article.news:id/bgh").click() # 登录页点击“。。。”
driver.find_element_by_xpath("//android.widget.LinearLayout[@index=4]").click() # 选择密码登录
driver.find_element_by_id("com.ss.android.article.news:id/bu").send_keys("xxxxxxx") # 输入账号
driver.find_element_by_id("com.ss.android.article.news:id/c5").send_keys("xxxxxxx") # 输入密码
driver.find_element_by_id("com.ss.android.article.news:id/a2o").click() # 点击登录
except Exception as e:
logging.error("登录错误,原因为:{}".format(e))
else:
logging.info("登陆成功...")
driver = android_driver()
login_opera(driver)
登录成功则日志输出如下:
2023-08-09 18:20:05,119 logging_test.py[line:21] INFO 启动今日头条APP...
2023-08-09 18:20:10,119 logging_test.py[line:27] INFO 开始登陆今日头条APP...
2023-08-09 18:21:07,120 logging_test.py[line:41] INFO 登陆成功...
3、抛出问题
上面示例代码成功地获取了日志信息,但这种写法只能作用于当前模块。而一个自动化测试项目往往有多个模块,如果在每个需要获取日志的模块都使用这样的方式,显然是不方便维护的。那么我们需要怎么解决呢?
4、解决思路
使用日志流处理流程。提供以下两种思路:
思路1:使用python代码实现日志配置。先创建日志记录器,并设置好Handler与日志格式,如上面的logging_test.py模块构造logger,其他模块采集日志时直接调用。
思路2:将日志的格式、输出路径等参数抽离出来放置在专门的配置文件里,如logging.conf,使用专门的模块处理,使用时直接在模块调用即可。
5、思路1——使用python代码实现日志配置示例
目录结构
test.py中需要采集日志时,从logging_test.py导入logger即可。也可以将logging_test.py里的代码进行进一步的封装,再调用,这里仅仅只是示例。
logging_test.py
import logging
# 创建日志记录器
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
# 设置日志输出格式
format= logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')
# 创建一个Handler用于将日志写入文件
logFile = './log.txt'
fh = logging.FileHandler(logFile, mode='a', encoding='utf-8')
fh.setLevel(logging.INFO)
fh.setFormatter(format)
logger.addHandler(fh)
# 同样的,创建一个Handler用于控制台输出日志
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
ch.setFormatter(format)
logger.addHandler(ch)
test.py
from appium import webdriver
from log.logging_test import logger
def android_driver():
desired_caps = {
"platformName": "Android",
"platformVersion": "10",
"deviceName": "PCT_AL10",
"appPackage": "com.ss.android.article.news",
"appActivity": ".activity.MainActivity",
"unicodeKeyboard": True,
"resetKeyboard": True,
"noReset": True,
}
logger.info("启动今日头条APP...")
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
return driver
def login_opera(driver):
'''登录今日头条操作'''
logger.info("开始登陆今日头条APP...")
try:
driver.find_element_by_id("com.ss.android.article.news:id/cji").click() # 点击【我知道了】
driver.find_element_by_id("android:id/button1").click() # 点击权限管理-确定按钮
driver.find_element_by_xpath("//android.widget.TabWidget/android.widget.RelativeLayout[@index=3]").click() # 点击未登录
driver.find_element_by_id("com.ss.android.article.news:id/a10").click() # 未登录页点击登录按钮
driver.find_element_by_id("com.ss.android.article.news:id/bgh").click() # 登录页点击“。。。”
driver.find_element_by_xpath("//android.widget.LinearLayout[@index=4]").click() # 选择密码登录
driver.find_element_by_id("com.ss.android.article.news:id/bu").send_keys("xxxxxx") # 输入账号
driver.find_element_by_id("com.ss.android.article.news:id/c5").send_keys("xxxxxx") # 输入密码
driver.find_element_by_id("com.ss.android.article.news:id/a2o").click() # 点击登录
except Exception as e:
logger.error("登录错误,原因为:{}".format(e))
else:
logger.info("登陆成功...")
driver = android_driver()
login_opera(driver)
运行test.py,结果如下:
2023-08-09 11:45:05,119 logging_test.py[line:21] INFO 启动今日头条APP...
2023-08-09 11:45:11,119 logging_test.py[line:27] INFO 开始登陆今日头条APP...
2023-08-09 11:45:20,120 logging_test.py[line:41] INFO 登陆成功...
6、思路2——日志格式配置示例
logger.conf文件:
[loggers] # loggers日志器对象列表,必须包含
keys=root, exampleLogger # 一定要包含root这个值,当使用无参函数logging.getLogger()时,默认返回root这个logger,其他自定义logger可以通过logging.getLogger("exampleLogger")方式进行调用
[handlers] # handlers处理器对象列表,必须包含
keys=consoleHandler, fileHandler # 定义声明handlers信息
[formatters] # formatters格式对象列表,必须包含
keys=form01,form02
[logger_root] # 对loggers中声明的logger进行逐个配置,且要一一对应,在所有的logger中,必须制定lebel和handlers这两个选项。对于非roothandler,还需要添加一些额外的option,如qualname、propagate等。handlers可以指定多个,中间用逗号隔开,比如handlers=fileHandler,consoleHandler,同时制定使用控制台和文件输出日志
level=DEBUG
handlers=consoleHandler, fileHandler
[logger_exampleLogger] # 配置日志处理器exampleLogger:设置日志级别、日志输出指定的处理器配置文件,如consoleHandler,fileHandler
level=DEBUG
handlers=consoleHandler, fileHandler
qualname=exampleLogger # qualname 表示它在logger层级中的名字,在应用代码中通过这个名字制定所使用的handler
propagate=0 # 可选项,其默认是为1,表示消息将会传递给高层次logger的handler
[handler_consoleHandler] # 日志处理器consoleHandler的配置文件
class=StreamHandler # 定控制台输出。将日志消息发送到输出到Stream,如std.out, std.err或任何file-like对象
level=DEBUG # 日志级别
formatter=form01 # 输出格式
args=(sys.stdout,)
[handler_fileHandler] # 日志处理器fileHandler的配置文件
class=FileHandler # 将日志输出至磁盘文件
level=DEBUG # 日志级别
formatter=form02 # 输出格式
args=('./log.txt', 'a', 'UTF-8') # 参数如未设置绝对路径,则默认生成在执行文件log.py的工作目录。指定日志文件的打开模式,默认为’a’
[formatter_form01] # 格式配置1
format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
[formatter_form02] # 格式配置2
format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
注意:
为了说明配置结构,这里的配置文件 logger.conf 里加了中文注释,实际使用时需要将注释去掉或改写成英文注释,否则会报编码错误。
配置文件中包含三大主要模块:loggers,handlers,formatters。这三个主要模块包含的内容都是通过keys进行指定,然后通过logger_key、handler_key、formatter_key对里面的key进行具体的设置。
配置handlers中的handler_consoleHandler的参数:指定日志输出到控制台、级别、输出格式、参数。
配置handlers中的handler_fileHandlers的参数:指定将日志输出至磁盘文件、设置日志级别、输出格式、参数等。
配置日志输出格式formatter_xxx,可配置多个,如:form01,form02。
读取配置文件,创建日志记录器logger:
baseLog.py
import logging.config
CON_LOG='./logger.conf' # 配置文件路径
logging.config.fileConfig(CON_LOG) # '读取日志配置文件'
logger = logging.getLogger('exampleLogger') # 创建一个日志器logger
调用示例
目录结构如下
test.py
from appium import webdriver
from log.baseLog import logger
def android_driver():
desired_caps = {
"platformName": "Android",
"platformVersion": "10",
"deviceName": "PCT_AL10",
"appPackage": "com.ss.android.article.news",
"appActivity": ".activity.MainActivity",
"unicodeKeyboard": True,
"resetKeyboard": True,
"noReset": True,
}
logger.info("启动今日头条APP...")
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
return driver
def login_opera(driver):
'''登录今日头条操作'''
logger.info("开始登陆今日头条APP...")
try:
driver.find_element_by_id("com.ss.android.article.news:id/cji").click() # 点击【我知道了】
driver.find_element_by_id("android:id/button1").click() # 点击权限管理-确定按钮
driver.find_element_by_xpath("//android.widget.TabWidget/android.widget.RelativeLayout[@index=3]").click() # 点击未登录
driver.find_element_by_id("com.ss.android.article.news:id/a10").click() # 未登录页点击登录按钮
driver.find_element_by_id("com.ss.android.article.news:id/bgh").click() # 登录页点击“。。。”
driver.find_element_by_xpath("//android.widget.LinearLayout[@index=4]").click() # 选择密码登录
driver.find_element_by_id("com.ss.android.article.news:id/bu").send_keys("xxxxxx") # 输入账号
driver.find_element_by_id("com.ss.android.article.news:id/c5").send_keys("xxxxxx") # 输入密码
driver.find_element_by_id("com.ss.android.article.news:id/a2o").click() # 点击登录
except Exception as e:
logger.error("登录错误,原因为:{}".format(e))
else:
logger.info("登陆成功...")
driver = android_driver()
login_opera(driver)
控制台、log.txt输出结果如下:
2023-08-09 11:30:35,119 logging_test.py[line:21] INFO 启动今日头条APP...
2023-08-09 11:30:40,119 logging_test.py[line:27] INFO 开始登陆今日头条APP...
2023-08-09 11:31:12,120 logging_test.py[line:41] INFO 登陆成功...
下面是我整理的2023年最全的软件测试工程师学习知识架构体系图 |
相信自己的力量,勇往直前,不惧困难与挫折。拥抱梦想,放飞心灵,用汗水浇灌希望,用努力铸就辉煌。每一次奋斗都是一次华丽蜕变,创造属于自己的人生传世,闪耀成为永恒之星。
热情点燃梦想,努力点亮未来,奋斗的征程永不停歇。坚持信念,追求卓越,超越自我创造辉煌。每一次努力都是成长的契机,让激情与毅力塑造辉煌人生。
奋斗是燃烧未来的火焰,努力是超越平凡的钥匙。相信自己的力量,追逐梦想的脚步不停歇。奋发向前,创造辉煌,每一次努力都是青春的宣言,让无限可能绽放人生的辉煌。