关键字驱动模型实战之测试运行
实验介绍
实验内容
在《Python Web 自动化测试入门实战》初级实验中给大家介绍过五种测试模型,其中线性模型、模块化驱动模型和行为驱动模型以实例给大家做了介绍。在本系列第七次和第八次实验给大家介绍了数据驱动模型。接下来会使用 pytest 框架实战关键字驱动模型。
在第十一次和第十二次中,我们分别对数据测试数据和对象操作进行了设计,本次实验我们将两者联系在一起,并且给测试项目添加日志,然后运行生成测试报告。
知识点
- 添加自动化测试用例
- 添加日志
- 日志深入记录
- 自动化项目运行
- 添加项目说明
代码获取
你可以通过下面的命令下载本节实验的代码到虚拟环境中,作为参照对比:
# 下载代码 wget https://labfile.oss-internal.aliyuncs.com/courses/3776/130.zip # 解压缩代码 unzip 130.zip
添加自动化测试用例
本节实验我们来收集测试用例,并且使用 pytest 框架的参数化功能,将测试用例添加到对象执行上。
添加共享 Fixture
通过 VS Code 工具在 /home/shiyanlou/Code/KeywordDrivenModel/case/ 下新建文件 conftest.py ,编写如下内容:
import pytest from selenium import webdriver @pytest.fixture(scope='session') def setup_teardown(): driver = webdriver.Firefox() yield driver driver.quit()
我们将浏览器的启动和关闭设置为前置条件和后置条件,作用域设置为 session 级别。整个自动化测试中只启动一次浏览器。
测试用例执行
通过 VS Code 工具在 /home/shiyanlou/Code/KeywordDrivenModel/case/ 下新建文件 test_case.py ,编写如下内容:
# -*-coding:utf-8-*- import pytest import os, sys current_path = os.path.abspath(os.path.dirname(__file__)) autotest_path = os.path.join(current_path, os.path.pardir) sys.path.append(autotest_path) from common.excel_util import ExcelUtil from action.operation import Operation def case(excel=None, sheet=None): return ExcelUtil(excel, sheet).get_case() @pytest.fixture(params=case(sheet='login')) def fixture_params(request): return request.param def test_run(setup_teardown, fixture_params): driver = setup_teardown Operation(driver).operate(fixture_params[0], fixture_params[1], fixture_params[2]) if __name__ == '__main__': pytest.main(['-s','case/test_case.py'])
在文件 test_case.py 下我们定义了三个函数,case() 函数是返回测试用例; fixture_params() 是代码在执行时会使用 pytest 内置的固件 request,并通过 request.param 来获取参数; test_run() 是使用我们在 /home/shiyanlou/Code/KeywordDrivenModel/action/operation.py 文件中定义的 Operation() 类中的 operate() 方法执行测试。
然后点击 VS Code 工具右上角的执行按钮执行文件,截图如下:
从结果中可以看到,一共执行了 12 条测试用例,与我们 Excel 表格中 12 条测试数据数量相吻合。
添加日志
日志是对软件执行时所发生事件的一种追踪方式。在本系列实验第九次实验中已经给大家介绍过了日志的使用。在此就直接上代码,不做介绍了。因为代码和第九次实验最后产生的 /home/shiyanlou/test/create_logging_file.py 文件代码相同。
添加创建日志代码
通过 VS Code 工具在 /home/shiyanlou/Code/KeywordDrivenModel/common/ 下新建文件 log_util.py ,编写如下内容:
import logging import datetime import os class LogUtil: def __init__(self): current_path = os.path.abspath(os.path.dirname(__file__)) autotest_path = os.path.join(current_path, os.path.pardir) file_name = datetime.datetime.now().strftime(autotest_path + "/log/%y-%m-%d-%H:%M") + '.log' self.file_formate = logging.Formatter('%(asctime)s - %(filename)s - %(levelname)s - %(message)s') self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.INFO) # 将日志写入磁盘 self.file_handler = logging.FileHandler(file_name, 'a', encoding='utf-8') self.file_handler.setLevel(logging.INFO) self.file_handler.setFormatter(self.file_formate) self.logger.addHandler(self.file_handler) def get_log(self): """获取 logger""" return self.logger def close_handler(self): """关闭 handler""" self.logger.removeHandler(self.file_handler) self.file_handler.close() def console_print(self): """控制台输出""" console = logging.StreamHandler() console.setLevel(logging.INFO) console.setFormatter(self.file_formate)
我们以运行时间命名日志文件,并且将其保存在 /home/shiyanlou/Code/KeywordDrivenModel/log/ 下。
修改 conftest.py
添加创建日志文件代码完成后,我们需要将日志在项目运行中使用。
修改 /home/shiyanlou/Code/KeywordDrivenModel/case/conftest.py 文件,添加日志写入,并且将 logger 和浏览器 driver 一样以参数的形式传入到测试用例执行中。
修改后的 /home/shiyanlou/Code/KeywordDrivenModel/case/conftest.py 文件内容如下:
import pytest import os, sys import logging from selenium import webdriver current_path = os.path.abspath(os.path.dirname(__file__)) autotest_path = os.path.join(current_path, os.path.pardir) sys.path.append(autotest_path) from common.log_util import LogUtil @pytest.fixture(scope='session') def setup_teardown(): driver = webdriver.Firefox() logging_file = LogUtil() logger = logging_file.get_log() logging_file.console_print() logger.info('START ---- browser') yield driver, logger driver.quit() logger.info('END ---- browser') logging_file.close_handler()
在浏览器启动成功后添加浏览器启动日志信息,浏览器关闭后添加浏览器运行结束的日志信息。
修改 test_case.py
接下来修改 /home/shiyanlou/Code/KeywordDrivenModel/case/test_case.py 文件中的 test_run() 函数。修改后的内容如下:
def test_run(setup_teardown, fixture_params): driver, logger = setup_teardown try: Operation(driver).operate(fixture_params[0], fixture_params[1], fixture_params[2]) logger.info("FINISHED ---- {} -- {} -- {}".format(fixture_params[0], fixture_params[1], fixture_params[2])) except: logger.exception("ERROR ---- {} -- {} -- {}".format(fixture_params[0], fixture_params[1], fixture_params[2]))
我们在对象操作运行结束后添加此条测试数据运行完成的日志信息,如果此条测试数据对象操作运行失败,则添加出错的日志信息。
然后点击 VS Code 工具右上角的执行按钮执行文件 /home/shiyanlou/Code/KeywordDrivenModel/case/test_case.py 。
代码执行结束后会在 /home/shiyanlou/Code/KeywordDrivenModel/log/ 下产生一个以时间命名且是 .log 格式的日志文件。我们来查看此文件内容,截图如下:
日志深入记录
在上小节添加日志中,大家有没有发现在修改 /home/shiyanlou/Code/KeywordDrivenModel/case/test_case.py 文件中 test_run() 函数时我们添加了一个 try...except... 语句,这是一个非常不合理的做法。如果当我们的测试数据在对象操作 Operation(driver).operate(fixture_params[0], fixture_params[1], fixture_params[2]) 中运行失败,那么此时程序会走 except,也就是说我们的测试函数 test_run() 依旧是成功的,在测试结果中展示的永远是成功,如果想要查看失败的测试用例只能在日志中查看,这显然是不明智的。
修改 test_case.py
接下来我们重新修改 /home/shiyanlou/Code/KeywordDrivenModel/case/test_case.py 文件中的 test_run() 函数。修改后的内容如下:
def test_run(setup_teardown, fixture_params): driver, logger = setup_teardown logger.info("START RUN ---- {} -- {} -- {}".format(fixture_params[0], fixture_params[1], fixture_params[2])) Operation(driver, logger).operate(fixture_params[0], fixture_params[1], fixture_params[2]) logger.info("FINISH ---- {} -- {} -- {}".format(fixture_params[0], fixture_params[1], fixture_params[2]))
我们在对象操作 Operation(driver, logger).operate(fixture_params[0], fixture_params[1], fixture_params[2]) 前添加开始执行的日志信息,运行结束后添加执行完成的日志信息。并且将 logger 以参数的形式传入 Operation() 类。
修改 operation.py
接着修改 /home/shiyanlou/Code/KeywordDrivenModel/action/operation.py 文件。
logger 传入后就需要接收,我们先来接收,然后将其继续传入 Browser() 类、 TimeSet() 类、 Element() 类。
在此只做 Element() 类的传入,其他的类似,大家可自行照此深入写入。
import os, sys current_path = os.path.abspath(os.path.dirname(__file__)) autotest_path = os.path.join(current_path, os.path.pardir) sys.path.append(autotest_path) from action.browser import Browser from action.time_set import TimeSet from action.element import Element class Operation: def __init__(self, driver, logger): self.driver = driver self.logger = logger def operate(self, obj, action, parameter=None): """ 对象操作 :param obj: :param action: :param parameter: :return: """ obj = obj.lower() if obj in ["browser", "driver", "webdriver"]: return Browser(self.driver).browser_operate(action, parameter) elif obj == "time": return TimeSet().time_operate(action, parameter) elif obj is None&nbs***bsp;obj == "": self.logger.warning("obj keyword is none&nbs***bsp;empty ---- {} -- {} -- {}".format(obj, action, parameter)) return # 如果不是其他的关键字对象,则就认为是元素对象 else: return Element(self.driver, self.logger).element_operate(obj, action, parameter)
修改 element.py
我们接着修改 /home/shiyanlou/Code/KeywordDrivenModel/action/element.py 文件。
首先修改 Element() 类下的构造函数 __init__() 。修改后的代码如下:
def __init__(self, driver, logger): self.driver = driver self.logger = logger然后修改 element_operate() 方法,修改后的代码如下:
def element_operate(self, local, action, parameter=None): """ 元素操作 :param local: :param action: :param parameter: :return: """ self.logger.info("element action start ---- {} -- {} -- {}".format(local, action, parameter)) element = self.__local_element(local) if element: self.logger.info("element local finished ---- {} -- {} -- {}".format(local, action, parameter)) else: self.logger.exception("element local fail ---- {} -- {} -- {}".format(local, action, parameter)) if action == "input" and parameter: element.send_keys(parameter) self.logger.info("element input finished ---- {} -- {} -- {}".format(local, action, parameter)) return elif action == "click": element.click() self.logger.info("element click finished ---- {} -- {} -- {}".format(local, action, parameter)) return elif action == "assert": AssertText(self.driver, element, parameter).equal() self.logger.info("element assert finished ---- {} -- {} -- {}".format(local, action, parameter)) return else: self.logger.exception("element action fail ---- {} -- {} -- {}".format(local, action, parameter)) return
给每一步都添加日志记录信息。
下面点击 VS Code 工具右上角的执行按钮,执行文件 /home/shiyanlou/Code/KeywordDrivenModel/case/test_case.py 。
代码执行结束后会在 /home/shiyanlou/Code/KeywordDrivenModel/log/ 下产生一个新的日志文件。我们来查看此文件内容,截图如下:
从日志信息中可以,记录的内容更丰富,更详细。在后期的问题定位中会更容易。
自动化项目运行
下面我们来编辑 /home/shiyanlou/Code/KeywordDrivenModel/run.py 文件,内容与第八次实验数据驱动模型中的执行文件 /home/shiyanlou/Code/DataDrivenModel/run.py 内容类似,就不做解释,直接写代码。
编辑 /home/shiyanlou/Code/KeywordDrivenModel/run.py 文件内容如下:
# -*- coding: utf-8 -*- """ Created on 2021-4-20 Project: KeywordDrivenModel @Author: Tynam """ import os import pytest current_path = os.path.abspath(os.path.dirname(__file__)) case_path = os.path.join(current_path, 'case') def run_case(): pytest.main(['-v', case_path]) def create_report(): run_case = """ cd %s & pytest %s --alluredir ./report/result/ """ % (current_path, case_path) generate_report = """ cd %s & allure generate ./report/result/ -o ./report/report/ --clean """ % (current_path) os.system(run_case) os.system(generate_report) if __name__ == '__main__': # run_case() create_report()
然后点击 VS Code 工具右上角的执行按钮执行文件,截图如下:
我们在 VS Code 工具中使用 Live Server 打开 /home/shiyanlou/Code/DataDrivenModel/report/report/index.html。截图如下:
至此,我们关键字驱动模型实验已经完成。
添加项目说明
编辑 /home/shiyanlou/Code/KeywordDrivenModel/readme.md 文件,添加项目说明,编写规则。
内容如下:
## 目录结构 - action:对象执行目录,包括浏览器操作、元素操作等。 - case:测试用例操作目录。 - common:公共层,存放数据文件的读写、日志写入等公共文件。 - data:数据目录,存放使用 Excel 写入的测试数据。 - log:日志目录,测试执行后产生的日志文件保存在此目录。 - report:存放测试报告。 - `run.py`:运行脚本并生成测试报告。 ## Excel 编写规则 ####浏览器操作 | 描述 | 对象 | 操作 | 参数 | | ------------ | ------- | ----- | ---- | | 最大化 | browser | max | | | 访问网页 | browser | open | url | | 关闭当前 tab | browser | close | | | 结束进程 | browser | quit | | ### 时间操作 | 描述 | 对象 | 操作 | 参数 | | -------- | ---- | ----- | -------------------- | | 时间等待 | time | sleep | 等待时间值(单位秒) | ### 元素操作 | 描述 | 对象 | 操作 | 参数 | 备注 | | ------------------------ | ------------- | ------ | ------------ | ------------------------------------------------------------- | | 元素定位 | 定位字符串 | | | 默认 CSS 定位 | | 其他方式定位 | by:定位字符串 | | | by 是定位方式,可选值:css、id、class、name、tag、link、xpath | | 输入框输入内容 | 定位字符串 | input | 输入的字符串 | | | 点击 | 定位字符串 | click | | | | 断言 | 定位字符串| assert | 预期字符串 | 只支持文本内容断言 | | Alert 弹窗文本字符串断言 | alert | assert | 预期字符串 | |
写入后在 VS Code 中预览,截图如下所示:
实验总结
实验知识点回顾:
- 添加自动化测试用例
- 添加日志
- 日志深入记录
- 自动化项目运行
- 添加项目说明
本次实验是对关键字驱动模型的实战练习。大家在以后的学习、工作中,需要灵活运用。思路,解决方案都是类似的,面对不同的项目测试、不同的测试场景都可以变通无碍。