美文网首页
pytest随手记-自定义mark、pytest.ini、doc

pytest随手记-自定义mark、pytest.ini、doc

作者: D_w | 来源:发表于2021-10-12 17:46 被阅读0次

mark标记

  1. 举例:某用例可以用@pytest.mark.xxx,则想要运行该条时需要加-m参数指定值为xxx,:如pycharm中写pytest.main(["-s", "test_server.py", "-m=xxx"]),cmd执行时pytest -v -m xxx,若不想执行则用 pytest -v -m "not xxx"
  2. 指定运行某函数也可在pycharm中用pytest.main(["-v", "test_server.py::TestClass::test_method"]),cmd下用pytest -v test_server.py::TestClass::test_method ,意为执行server.py文件下TestClass类中test_method方法,也可选择多个节点运行,中间用逗号隔开:
pytest.main(["-v", "test_server.py::TestClass", "test_server.py::test_send_http"])
  1. 用 -k 匹配用例名称执行,如 pytest -v -k http (指定匹配带有http的用例)、pytest -k "not send_http" -v(去掉带有send_http的用例)、pytest -k "http or quick" -v(同时带quick的用例)

基础用例a失败,则依赖a用例结果的b、c用例直接跳过且标记为xfail

举个例子

#encoding=utf-8
import pytest

canshu = [{"user": "amdin", "psw": ""}]

@pytest.fixture(scope="module")
def login(request):
    user = request.param["user"]
    psw = request.param["psw"]
    print("正在操作登录,账户:%s,密码:%s" %(user,psw))
    if psw:
        return True
    else:
        return False

@pytest.mark.parametrize("login", canshu, indirect=True)
class Test_xx():
    def test_01(self,login):
        '''用例1登录'''
        result = login
        print("用例1:%s" % result)
        assert result == True

    def test_02(self,login):
        result = login
        print("用例2,登录结果:%s" %result)
        if not result:
            pytest.xfail("登录不成功,标记为xfail")

        assert 1 == 1

    def test_03(self,login):
        result = login
        print("用例3,登录结果:%s" %result)
        if not result:
            pytest.xfail("登录不成功,标记为xfail")

        assert 1 == 1

if __name__ == "__main__":
    pytest.main(["-s", "pratice.py"])

结果如图


mark_xfail

可以看到有两个用例判断登录失败后置为xfail且被ignore

pytest.ini配置文件

pytest.ini pytest的主配置文件,可以改变pytest的默认行为,该文件放在python项目的根目录,基本格式如下:

# 保存为pytest.ini文件

[pytest]

addopts = -rsxX
xfail_strict = true

使用pytest --help指令可以查看pytest.ini的设置选项

[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg file found:

  markers (linelist)       markers for test functions
  empty_parameter_set_mark (string) default marker for empty parametersets
  norecursedirs (args)     directory patterns to avoid for recursion
  testpaths (args)         directories to search for tests when no files or dire

  console_output_style (string) console output: classic or with additional progr

  usefixtures (args)       list of default fixtures to be used with this project

  python_files (args)      glob-style file patterns for Python test module disco

  python_classes (args)    prefixes or glob names for Python test class discover

  python_functions (args)  prefixes or glob names for Python test function and m

  xfail_strict (bool)      default for the strict parameter of 
  addopts (args)           extra command line options
  minversion (string)      minimally required pytest version

具体参考https://www.cnblogs.com/yoyoketang/p/9550648.html这篇

doctest测试框架

doctest从字面意思上看,那就是文档测试。doctest是python里面自带的一个模块,它实际上是单元测试的一种。官方解释:doctest 模块会搜索那些看起来像交互式会话的 Python 代码片段,然后尝试执行并验证结果。个人感觉就是单元测试。
doctest测试用例可以放在两个地方

  • 函数或者方法下的注释里面
    例如:
def multiply(a, b):
    """
    fuction: 两个数相乘
    >>> multiply(4, 3)
    12
    >>> multiply('a', 3)
    'aaa'
    """
    return a * b
if __name__ == '__main__':
    import doctest
    doctest.testmod(verbose=True)
------------------------输出------------------------
Trying:
    multiply(4, 3)
Expecting:
    12
ok
Trying:
    multiply('a', 3)
Expecting:
    'aaa'
ok
1 items had no tests:
    __main__
1 items passed all tests:
   2 tests in __main__.multiply
2 tests in 2 items.
2 passed and 0 failed.
Test passed.
  • 模块的开头
'''
fuction: 两个数相乘
>>> multiply(4, 8)
12
>>> multiply('a', 5)
'aaa'
'''

def multiply(a, b):
    """
    fuction: 两个数相乘
    """
    return a * b
if __name__ == '__main__':
    import doctest
    doctest.testmod(verbose=True)
-------------------------输出---------------------
Failure
<Click to see difference>
**********************************************************************
File "F:/testpython/pratice.py", line 4, in pratice
Failed example:
    multiply(4, 8)
Expected:
    12
Got:
    32
Failure
<Click to see difference>
**********************************************************************
File "F:/testpython/pratice.py", line 6, in pratice
Failed example:
    multiply('a', 5)
Expected:
    'aaa'
Got:
    'aaaaa'

pytest框架是可以兼容doctest用例,执行的时候加个参数 --doctest-modules ,这样它就能自动搜索到doctest的用例
$ pytest -v --doctest-modules xxx.py
doctest独立文件
doctest内容也可以和代码抽离开,单独用一个.txt文件保存,在当前xxx.py同一目录新建一个xxx.txt文件,写入测试的文档,要先导入该功能,导入代码前面也要加>>>,如

>>> from xxx import multiply
>>> multiply(4, 3)
12
>>> multiply('a', 3)
'aaa'

cmd执行“python -m doctest -v xxx.txt”测试结果

pytest-html

  • 安装pytest-html
    pip install pytest-html
  • 执行,到pytest用例目录下
    pytest --html=report.html
    想要指定生成路径的话:pytest --html=./report/report.html
  • 报告独立显示
    pytest --html=report.html --self-contained-html
    -失败截图可以写到conftest,py文件里,这样用例运行时,只要检测到用例实例,就调用截图的方法,并且把截图存到html报告上
# conftest.py文件
# coding:utf-8

from selenium import webdriver
import pytest


driver = None

@pytest.mark.hookwrapper
def pytest_runtest_makereport(item):
    """
    当测试失败的时候,自动截图,展示到html报告中
    ** 作者:上海-悠悠 QQ交流群:588402570**
    :param item:
    """
    pytest_html = item.config.pluginmanager.getplugin('html')
    outcome = yield
    report = outcome.get_result()
    extra = getattr(report, 'extra', [])

    if report.when == 'call' or report.when == "setup":
        xfail = hasattr(report, 'wasxfail')
        if (report.skipped and xfail) or (report.failed and not xfail):
            file_name = report.nodeid.replace("::", "_")+".png"
            screen_img = _capture_screenshot()
            if file_name:
                html = '<div><img src="data:image/png;base64,%s" alt="screenshot" style="width:600px;height:300px;" ' \
                       'onclick="window.open(this.src)" align="right"/></div>' % screen_img
                extra.append(pytest_html.extras.html(html))
        report.extra = extra

def _capture_screenshot():
    '''
    ** 作者:上海-悠悠 QQ交流群:588402570**
    截图保存为base64,展示到html中
    :return:
    '''
    return driver.get_screenshot_as_base64()


@pytest.fixture(scope='session', autouse=True)
def browser(request):
    global driver
    if driver is None:
        driver = webdriver.Firefox()

    def end():
        driver.quit()
    request.addfinalizer(end)
    return driver

用例文件,分为两个

# test_01.py文件

from selenium import webdriver
import time

#** 作者:上海-悠悠 QQ交流群:588402570**

def test_yoyo_01(browser):

    browser.get("https://www.cnblogs.com/yoyoketang/")
    time.sleep(2)
    t = browser.title
    assert t == "上海-悠悠"
# test_02.py文件

from selenium import webdriver
import time

# ** 作者:上海-悠悠 QQ交流群:588402570**

def test_yoyo_01(browser):

    browser.get("https://www.cnblogs.com/yoyoketang/")
    time.sleep(2)
    t = browser.title
    assert "上海-悠悠" in t

在cmd中运行 pytest --html=report.html --self-contained-html,生成报告

含失败截图
失败重试
需要 pip install pytest-rerunfailures 安装插件(这个插件目前这样安装会报错,可以在豆瓣等网站上下载好包在本地安装,也可以通过pycharm安装)
重跑命令:py.test --reruns 1 --html=report.html --self-contained-html,--reruns 1代表重跑一次
修改报告

添加描述(Description)列,添加可排序时间(Time)列,并删除链接(Link)列:(说实话conftest.py中的钩子函数和除fixture功能外的其他用法都还一头雾水)

from datetime import datetime
from py.xml import html
import pytest

@pytest.mark.optionalhook
def pytest_html_results_table_header(cells):
    cells.insert(2, html.th('Description'))
    cells.insert(1, html.th('Time', class_='sortable time', col='time'))
    cells.pop()

@pytest.mark.optionalhook
def pytest_html_results_table_row(report, cells):
    cells.insert(2, html.td(report.description))
    cells.insert(1, html.td(datetime.utcnow(), class_='col-time'))
    cells.pop()

@pytest.mark.hookwrapper
def pytest_runtest_makereport(item, call):
    outcome = yield
    report = outcome.get_result()
    report.description = str(item.function.__doc__)

相关文章

网友评论

      本文标题:pytest随手记-自定义mark、pytest.ini、doc

      本文链接:https://www.haomeiwen.com/subject/kkedoltx.html