PythonUI 测试框架pytest(用例筛选/断言/测试报告/数据驱动)
一、用例筛选
unittest 手动添加测试用例: suite.addTests( )
pytest 在需要筛选的用例的上添加@pytest.mark.smoke
-
在pytest.ini文件中加上标签名:smoke
[pytest] markers = success error smoke fail
-
在TestLogin类上面加@pytest.mark.smoke
-
terminal中运行 pytest -m "smoke"
标记整个类:类上面加 @pytest.mark.tagname
标记的组合:
- and 必须同时具备两个标签,pytest -m "demo and error"
- or 只需要满足其中的一个标签,就会运行 pytest -m "demo or error"
- not "success and not demo"
import pytest from futureloan_web.middleware.MiddleHandler import MidInitHandler from middleware.pages.login import LoginPages from data.login_data import login_error,login_success,login_invalid class TestLogin(): '''登录''' handler = MidInitHandler() @pytest.mark.error @pytest.mark.parametrize("test_info", login_error) def test_login_error(self,test_info,driver): login_page = LoginPages(driver) actual = login_page.get().login_fail( username=test_info["username"], password=test_info["password"], ).get_error_message() # 实际结果和预期结果比对,日志记录,错误处理 try: assert actual == test_info["expected"] self.handler.logger.info("测试用例通过") except AssertionError as e: self.handler.logger.error("测试用例不通过") raise e @pytest.mark.success @pytest.mark.parametrize("test_info", login_success) def test_login_success(self,test_info,driver): login_page = LoginPages(driver) actual = login_page.get().login_success( username=test_info["username"], password=test_info["password"], ).get_account_name() # 实际结果和预期结果比对,日志记录,错误处理 try: assert actual == test_info["expected"] self.handler.logger.info("测试用例通过") except AssertionError as e: self.handler.logger.error("测试用例不通过") raise e @pytest.mark.error @pytest.mark.parametrize("test_info", login_invalid) def test_login_invalid(self,test_info,driver): """登录未授权""" login_page = LoginPages(driver) actual = login_page.get().login_fail( username=test_info["username"], password=test_info["password"] ).get_invalid_message() try: assert actual == test_info["expected"] except AssertionError as e: self.handler.logger.error("测试用例不通过") raise e
注意:用例标记的时候,标签如果有逻辑运算,一定要加双引号
一个类或者是方法或者是函数,都可以加多个标签,直接在他们的上面打多个标签即可
@pytest.mark.smoke @pytest.mark.error def test_demo_no_class(self): pass
二、断言
--unittest断言使用asserTrue/assertEqual等系列,如assertTrue(v == resp[k])
--pytest断言使用内置的关键字 assert,如assert v == resp
try: assert actual == test_info["expected"] except AssertionError as e: self.handler.logger.error("测试用例不通过") raise e
三、测试报告
安装:pip install pytest-html
执行:pytest -m "demo" --html=reports.html
时间戳生成测试报告:使用脚本方式运行:run.py
"运行测试用例" import pytest import datetime ts = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") if __name__ == '__main__': pytest.main(["--html={}report.html".format(ts)])
如果是多个参数: pytest.main(['--html={}.html'.format(ts),"-m demo"])
用例的执行顺序:从上到下
四、数据驱动
用unittest框架去测试
import unittest import ddt from lenom.aa import ExcelHandler def login(username=None, password=None): """登录""" if (not username) or (not password): # 用户名或者密码为空 return {"msg": "empty"} if username == 'yuz' and password == '123456': # 正确的用户名和密码 return {"msg": "success"} return {"msg": "error"} cases = ExcelHandler('cases.xlsx').read_data('login') @ddt.ddt class TestLogin(unittest.TestCase): @ddt.data(*cases) def test_login(self,case_info): data = eval(case_info['data']) username = data["username"] password = data["password"] expected_response = case_info["expected"] actual_response = login(username, password) self.assertTrue(expected_response == actual_response['msg'])
用pytest 进行数据驱动
import pytest from data.login_data import login_success,login_error from middleware.pages.login import LoginPage from middleware.MiddleHandler import MidInitHandler class TestLogin: """登录""" handler = MidInitHandler() @pytest.mark.parametrize("test_info", login_error) def test_login_fail(self,test_info,driver): """登录失败""" login_page = LoginPage(driver) actual = login_page.get().login_fail( username=test_info["username"], password=test_info["password"], ).get_error_message() try: assert test_info["expected"] in actual self.handler.logger.info("测试用例通过:{}".format(test_info["title"])) except Exception as e: self.handler.logger.error("测试用例不通过:{}".format(test_info["title"])) raise e
注意:两个test_info名称必须一致
在使用pytest.mark.paramatrize 做数据驱动的时候,pytest 和 unittest 不兼容
如果你想使用 pytest 的数据驱动,就不要继承 unittest.TestCase
如果你想使用 unittest写用例, 就要用 unittest 的数据驱动