首页 > 其他 > 详细

pytest入门

时间:2020-06-09 10:16:39      阅读:50      评论:0      收藏:0      [点我收藏+]

Pytest简介

本文介绍了pytest的安装,fixture的使用,参数化,命令行,断言,分组mark运行等

介绍了如何利用pytest生成log或html报告,以及pytest-bdd行为驱动模块的使用

入门

安装

pip install -U pytest python -m pytest --version

示例

import pytest
import time

def test_equal():
    assert (1, 2, 3) == (1, 2, 3)

def test_not_equal():
    assert 1 != 2

@pytest.mark.cal
def test_add():
    assert 1 + 1 == 2

@pytest.mark.cal
def test_sub():
    assert 1 - 1 == 0
# pytest 遵循测试发现规则,即当前目录及子目录下所有 test_*.py 或 *_test.py文件,和以test_开头的方法

运行pytest

pytest ./testdemo2/test_simple.py 也可以直接在IDE中运行,注意,右键运行时,只运行鼠标focus的函数,focus空白时运行该文件中所有函数

-v 显示详细信息 -k "xxx" 运行方法名中包含字符串的格式

-m 依照pytest.mark的分组进行测试 pytest --duration=3 运行最慢的三个

--maxfail=2 2次失败后停止

按节点运行测试

pytest test_Mod.py::test_func pytest test_mod.py::TestCase::test_method

按包运行测试

pytest --pyargs pkg.testing

pytest --showlocals # 在追溯信息中显示局部变量
pytest -l           # 显示局部变量 (简写)
pytest --tb=auto    # (默认) 第1和最后1条使用详细追溯信息,其他使用简短追溯信息
pytest --tb=long    # 详尽,信息丰富的追溯信息格式
pytest --tb=short   # 简短的追溯信息格式
pytest --tb=line    # 每个失败信息一行
pytest --tb=native  # Python标准库格式
pytest --tb=no      # 不使用追溯信息s

pytest -ra 显示摘要

-f fail -E error -s skip -x xfail -X xsuccess -p success -P success and have print -a all

生成测试摘要

pytest --junitxml=path

pytest --resultlog=path

pip install pytest-html -> pytest -v -m xx --html=path

可以在代码中直接传入命令行参数

if __name__ == ‘__main__‘:
    pytest.main([‘-v‘, ‘-m cal‘, ‘--html=test1.html‘])

断言

异常检测

def add(a, b):
    def throw_type_error(a):
        if not isinstance(a, int) and not isinstance(a, float):
            raise TypeError(‘please input nums‘)
    throw_type_error(a)
    throw_type_error(b)
	return a + b 

def test_add_exception():
    with pytest.raises(TypeError):
        add(‘a‘, ‘b‘)
def test_add_expection_message():
    with pytest.raises(TypeError) as error_info:
        add(‘a‘, ‘b‘)
    error_message = error_info.value.args[0]
# 确定场景,add时需要抛出异常 
# warining 断言
pytest.warns

自定义

hook方法中的pytest_assertrepr_compare

暂时不会用

参数化

使用装饰器

import pytest
class Calculator:
    def __init__(self, num1, num2):
        self.num1 = num1
        self.num2 = num2

    def add(self):
        return self.num1 + self.num2

    def sub(self):
        return self.num1 - self.num2

@pytest.mark.parametrize(‘num1,num2,result‘, [
    (1, 1, 2),
    (1, 2, 3),
    (3, 2, 2)
])
def test_calculator_add(num1, num2, result):
    cal = Calculator(num1, num2)
    assert result == cal.add()
@pytest.mark.parametrize(‘num1,num2,result‘, [
    (1, 1, 2),
    (1, 2, 3),
    (3, 2, 2)
])
def test_calculator_add(num1, num2, result):
    cal = Calculator(num1, num2)
    assert result == cal.add()

parameter = [
    (Calculator(1, 1), 2),
    (Calculator(2, 3), 5),
    (Calculator(1, 4), 3)
]
cal_ids = [f"{p[0].num1} + {p[0].num2} ={p[1]}" for p in parameter]
@pytest.mark.parametrize(‘cal_test,result‘,parameter,ids=cal_ids)
def test_cal_sum(cal,result):
    assert result == cal.add()

pytest fixtures and scope

fixture可以在测试之前或之后运行,用来准备测试环境

全局共享的fixture配置可以写入conftest.py文件中

共享的测试数据也可以写入conftest.py文件

@pytest.fixture()
def some_num():
    return 4
def test_some_num(some_num):
    assert some_num == 4
# 如利用selenium测试时所需准备的driver
@pytest.fixture()
def browser(scope=‘session‘):
    b = webdriver.Chrome()
    b.implicitly_wait(10)
    yield b
    b.quit()
# fixture使用yield函数之后的语句作为teardonw函数

使用addfinalizer(func__ name__)实现无论测试套中是否存在异常,都调用teardown函数,且支持多个teardown

fixture工厂函数
# 方法一
@pytest.fixture
def make_customer_record():

    def _make_customer_record(name):
        return {
            "name": name,
            "orders": []
        }

    return _make_customer_record


def test_customer_records(make_customer_record):
    customer_1 = make_customer_record("Lisa")
    customer_2 = make_customer_record("Mike")
    customer_3 = make_customer_record("Meredith")
# 方法二
import pytest

class Customer:
    def __init__(self, name):
        self.name = name
        self.orders = []

    def __call__(self):
        return {‘name‘: self.name, ‘orders‘: self.orders}

    def destroy(self):
        self.name = None
        self.orders = None

@pytest.fixture
def make_customer_record():
    created_records = []

    def _make_customer_record(name):
        obj = Customer(name=name)
        record = obj()
        created_records.append(obj)
        return record

    yield _make_customer_record

    for obj in created_records:
        obj.destroy()

def test_customer_records(make_customer_record):
    customer_1 = make_customer_record("Lisa")
    customer_2 = make_customer_record("Mike")
    customer_3 = make_customer_record("Meredith")
    print(customer_1, customer_2, customer_3)
"""
{‘name‘: ‘Lisa‘, ‘orders‘: []} {‘name‘: ‘Mike‘, ‘orders‘: []} {‘name‘: ‘Meredith‘, ‘orders‘: []}
"""
使用fixture实现参数化

基本简单参数化还是以parameterize为主

这里举例使用params和ids对数据进行预处理

def idfn(fixture_value):
    if fixture_value == 0:
        return "eggs"
    else:
        return None

@pytest.fixture(params=[0,1],ids=idfn)
def b(request):
    return request.param

def test_b(b):
    pass
scope用来规定fixture的作用范围

其中,存在包含关系,可以多重包含从而实现每个setup,teardown和setupclass,teardownclass的关系

Scope DESC
session 一次run中的所有case
module 一个.py文件
class 类的范围
function(default) 方法(函数)的范围

--setup-show

文件配置

filename desc
pytest.ini 改变pytest的默认行为
conftest.py fixture配置
tox.ini tox tools
setup.cfg influence setup.py
[pytest]
addopts = -rsxX -l --tb=short --strict
; --rsxX 表示pytest报告 所有的用例被跳过,预计失败,预计不符的原因
xfail_strict = true
markers = 
    smoke: smoke test
    get: get test
    cal: cal test

注意,pytest.ini文件中含有中文时有可能会gbk编码错误

pytest --markers查看注册的marker

pytest-bdd的简单使用

需求描述

test.feature文件

Feature: 测试woniuboss登陆
  ? ? 描述:woniuboss登陆功能测试

 Scenario: 输入用户名密码登陆
   Given 用户名:wncd000 ,密码:woniu123,验证码:000
   When 打开页面:http://172.16.5.31:8080/WoniuBoss4.0/login
   And 输入用户名,密码,验证码
   Then 我可以在结果页面看到:首页 - 蜗牛BOSS系统
  • 一个需求文件中只能有一个Feature字段, 可以包含多个Scenario(用户场景)
  • Given->When->Then类似与准备->执行->验证/清理的流程
  • Given: 一般可以用来做预置条件/数据准备, 下面第一个And也属于Given
  • When下面的量And都属于When, 一般是操作步骤, <用户>等只是用来提醒使用的是Given中的数据, 也可以不使用<>
  • Then: 一般用于验证结果(断言), 也可以进行清理数据
import time
import pytest
from selenium import webdriver
from pytest_bdd import scenarios, given, when, then, parsers

@pytest.fixture(scope=‘module‘)
def browser():
    driver = webdriver.Chrome()
    # b = webdriver.Firefox()
    driver.implicitly_wait(3)
    yield driver
    driver.quit()

scenarios(r‘./test.feature‘)

@given(parsers.parse(‘用户名:{username} ,密码:{password},验证码:{verify_code}‘))
def user(browser, username, password, verify_code):
    return dict(username=username, password=password, verify_code=verify_code)

@when(parsers.parse(‘打开页面:{url}‘))
def open_page(browser, url):
    browser.get(url)

@when(‘输入用户名,密码,验证码‘)
def do_login(browser, user):
    browser.find_element_by_name(‘userName‘).send_keys(user[‘username‘])
    browser.find_element_by_name(‘userPass‘).send_keys(user[‘password‘])
    browser.find_element_by_name(‘checkcode‘).send_keys(user[‘verify_code‘])
    browser.find_element_by_css_selector(‘#form-login > div > div > div.modal-footer > button‘).click()

@then(parsers.parse(‘我可以在结果页面看到:{message}‘))
def see_results(browser, message):
    time.sleep(1)
    assert str(message) in browser.page_source

Flask简单介绍和相关测试

flask 运行环境 python -m venv flask_env

windows环境下 -> flask_env -> Script -> activate.bat

注意 flask_env为独立的配置环境,需要在其目录下安装 pip install flask -> set FLASK_APP=flaskblog.py -> flask run

* Serving Flask app "flaskblog.py"
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

使用 set FLASK_ENV=development

可以动态观察网页

pytest入门

原文:https://www.cnblogs.com/WheelCode/p/13070627.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!