pytest 入门学习

Pytest 入门学习

pytest是一个非常成熟的全功能的Python测试框架,主要特点有以下几点:

简单灵活,容易上手;

支持参数化;

能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests);

pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)、pytest-rerunfailures(失败case重复执行)、pytest-xdist(多CPU分发)等;

测试用例的skip和xfail处理;

可以很好的和jenkins集成;

一、安装

安装

pip install -U pytest

检查是否安装成功

pytest --version

This is pytest version 4.5.0, imported from c:\python27\lib\site-packages\pytest.pyc

查看帮助命令

pytest -h

二、快速入门

创建一个test_sample.py

def func(x):

     return x + 1

class TestCase():

     def test_answer(self):

           assert func(3) == 5

运行用例

命令行通过以下命令运行:

  1. 运行所有文件:pytest

  2. 运行单个文件:pytest test_sample.py

运行结果:

结论:

从上面看出,当用例运行失败时,会在控制台打印具体的错误信息,包含用例信息及具体错误代码和预期结果。错误信息一目了然。

非命令行运行

代码右键运行或直接从pytest.main()运行,返回结果如下:

三、pytest用例识别

pytest会找当前以及递查找子文件夹下面所有的test_.py或_test.py的文件,把其当作测试文件
在这些文件里,pytest会收集下面的一些函数或方法,当作测试用例:

1、不在类定义中的以test_开头的函数或方法
2、在以Test开头的类中(不能包含init方法),以test_开头的方法
3、pytest也支持unittest模式的用例定义

四、运行用例

1、运行单个用例

使用命令,pytest+文件名 运行,如运行test_class.py

pytest test_class.py

2、运行多个用例

运行多个用例,使用命令pytest

3、运行指定用例

3.1通过匹配关键字,运行用例

使用命令,pytest -k keyword 运行指定关键字用例

3.2通过用例标记,运行用例

1)用例标记:pytest允许为测试用例添加属性通过 pytest markers,@pytest.mark,定义方法: @pytest.mark.<name>

2)运行标记的用例,如运行被标记falled的用例:pytest -m falled

结论:

由上图可看出,文件中被标记为falled的用例被执行。

3、运行文件夹下的用例

使用命令,pytest + 文件夹,可运行该文件夹下的用例,如运行testing文件夹下的用例

结论:

通过 pytest+文件名/ 命令,可运行该文件夹下的所有用例。

4、运行模块下类内指定的用例

使用命令,pytest+文件名+类名+方法名,指定运行测试用例,格式为:pytest::test_.py::Test::test

结论:

由上图可以看到,使用命令 pytest::test_sample.py::TestCase::test01,可以运行test_sample.py文件中TestCase类下的test01方法。

五、运行用例,显示指定结果信息

运行测试用例,显示总的结果信息,使用命令 pytest -ra

运行测试用例,显示通过的结果信息,使用命令 pytest -rp

运行测试用例,显示错误结果信息警告信息,使用命令 pytest -rE

运行测试用例,显示跳过结果信息,使用命令 pytest -rs

======================== short test summary info ========================

SKIPPED [1] test_skip_case.py:4: unconditional skip

SKIPPED [1] test_skip_case.py:9: unconditional skip

六、环境准备和环境清理

pytest使用Fixture功能为测试用例进行环境准备和环境清理,相当于unittest中的setup\teardown,

setupClass\teardownClass。同时对于传统的setup/teardown函数做了显著的改进:

1)测试fixture有明确的名称,通过在函数/模块/类或者整个项目中激活来使用。

2)测试fixture是模块化的实现,使用fixture名即可触发特定的fixture,fixture可以在其他fixture中进行使用

3)测试fixture不仅可以进行简单的单元测试,也可以进行复杂的功能测试。可以根据配置和组件的选项进行参数化定制测试,或者跨函数/类/模块或者整个测试过程进行测试。

1、环境准备

使用@pytest.fixture装饰器来设置一个函数为测试fixture,后面的测试函数调用到fixture名称时,pytest会检测到该fixture并加载其中的数据作为参数传入。定义fixture的方式:在单个测试文件中定义

、多个文件共享fixture、通过设置fixture中的scope指定作用范围定义,格式为@pytest.fixture(scope=session/module/class/function),其中作用范围大小为:session>module>class>function。具体实现详见例子~

1.1单个函数定义fixture

1)创建一个文件test_fixture01.py

@pytest.fixture()  # 定义some_data函数为测试fixture

def some_data():

       return 42

def test_some_data(some_data):  # 测试函数调用some_data,并做断言

       assert some_data == 42

2)调用并执行以上文件:执行命令 pytest --setup-show test_fixture01.py

E:\自动化\pytest框架学习\learn_fixture>pytest --setup-show test_fixture01.py

========================test session starts ============================

platform win32 -- Python 3.7.2, pytest-5.2.2, py-1.8.0, pluggy-0.13.0

rootdir: E:\乐乎自动化\pytest框架学习\learn_fixture

plugins: forked-1.1.1, html-2.0.0, metadata-1.8.0, xdist-1.30.0

collected 1 item

test_fixture01.py

SETUP F some_data

test_fixture01.py::test_some_data (fixtures used: some_data).

TEARDOWN F some_data

========================== 1 passed in 0.12s ==========================

结论:

由上执行结果可以看到,在执行test_some_data用例时,test_some_data调用了测试fixture some_data,并在用例执行前后进行了setup和teardown操作。

1.2多个文件共享fixture

在测试用例实现过程中,当需要使用来自多个文件的fixture时,可以将这些fixture函数写到conftest.py文件中。使用时,不需要导入fixture函数,pytest会自动检索。

fixture函数的使用从测试类开始,到测试模块,然后是conftest.py文件,然后是内置的插件和第三方插件。也可以使用conftest为本地目录实现插件。

1)修改test_fixture01.py文件,分别改为两个文件,将测试fixture函数存入到conftest.py文件中,测试函数另起一个文件为test_fixture02.py

content of conftest.py

@pytest.fixture()  # 定义some_data函数为测试fixture

def some_data():

       return 42

content of test_fixture02.py

 def test_some_data(some_data):  # 测试函数调用some_data,并做断言

        assert some_data == 42

2)执行多个文件:执行命令 pytest --setup-show test_fixture01.py test_fixture02.py

结论:

由上图执行结果可看到,当将测试fixture函数放在conftest.py文件中,测试用例调用时,可实现多个文件共享fixture函数。

1.3通过设置fixture中的scope指定作用范围

1)指定@pytest.fixture(scope="function"),执行文件时,所有测试文件的每个function函数执行时都会调用fixture函数一次。【不指定情况下,默认为funtion】

结论:

当设置scope="funtion"时,每个用例执行前后都会调用一次function。

2)指定@pytest.fixture(scope="class"),执行文件时,每个类执行前后只调用测试fixture一次。

结论:

当设置sope="class"时,在调用类时,只调用一次funtion。

3)指定@pytest.fixture(scope="module"),执行文件时,只调用fixture一次

创建一个test_fixture04.py包含两个类及一个测试函数,并执行文件:

结论:

从上图可以看到,在执行测试文件时,执行前和执行后只进行了一次funtion的调用。

4)指定@pytest.fixture(scope="session"),执行一个会话时,只调用fixture一次。

注:一个会话是一次文件的调用,可以同时调用多个文件。

结论:

当设置scope="session"时,只是在整个会话开始前和结束后调用一次function。

2、环境清理

pytest支持在fixture退出作用域的时候执行相关的清理/结束代码。使用yield而不是return关键字的时候,yield后面的语句将会在fixture退出作用域的时候被调用来清理测试用例。

1)创建一个文件test_fixture06.py,包含test fixture和test function两部分

import pytest

@pytest.fixture(scope=**"module"**)
def something():

      print(**"**\n**哈哈哈哈****"**)   # setup部分数据

      yield              # 使用yield后面的语句将会在fixture退出作用域的时候被调用来清理测试用例

      print(**"****结束了?****"**)

 def test_smtp(something):

      print(**"****测试中。。。。****"**)

2)运行文件:pytest -s test_fixture06.py

七、设置断言

断言,每个测试用例都需要断言。unittest中使用unittest自带的断言机制,与unittest不同的时,pytest使用的是python自带的assert关键字来进行断言。

assert关键字后面可以接一个表达式,只要表达式的最终结果为True,那么断言通过,用例执行成功,否则用例执行失败。断言失败有详细的用例失败描述。

1、断言

代码:

def f():

      return 3

def test_function():

      assert f() == 4

执行结果:

总结:

从执行结果可以看到,用例断言失败了,且有详细的失败信息描述,可以一眼看出是哪儿出了问题。

2、断言异常抛出

八、用例参数化

参数化测试是用于一些测试流程一样,测试数据不同的测试用例,以此来简化代码。

pytest支持使用fixture中通过param="参数集"初始化需要传入的参数,再将fixture作为参数传入用例中实现参数化。也可通过使用parametrize支持多个参数化传入。

1、参数化fixture(参数化1个)

校验用户弱密码~

users文件:

[

 {"name":"jack","password":"Iloverose"},

 {"name":"rose","password":"Ilovejack"},

 {"name":"tom","password":"password123"},

 {"name":"mike","password":"password"},

 {"name":"james","password":"AGoodPasswordWordShouldBeLongEnough"}

 ]

用例文件:

   '''用例需求:

    校验多个用户、密码是否存在弱密码。

    用例设计:

    使用参数化形式,一个测试方法传入user集参数,使用例一次性校验所有用户 
    是否存在弱密码。

 '''

import pytest

import json

users = json.loads(open(**'./user.json'**, **'r'**).read())  # 从user.json文件中读取出用户数据

class TestUserPasswordWithParam():

@pytest.fixture(params=users)    # 将user作为参数传入,并返回user中的每个用户信息。再将此fixture作为参数传入到用例中数据

def user(self, request):

    user_info = request.param         # 使用request.param从users中一个一个地拿出数据并返回

    return user_info

def test_user_password(self, user):

    password = user[**'password'**]

    assert len(password) >= 6

    msg = **"****用户****%s****存在弱密码****"** % (user[**'name'**])

    assert password != **'password'**, msg

    assert password != **'password123'**, msg

测试结果:

总结:

从上面运行结果可以看到,用例一共运行了5次。

2、parametrize多参数(参数化多个)

此功能,类似unittest中的ddt数据驱动模式

@pytest.mark.parametrize 装饰器可以让我们每次参数化fixture的时候传入多个项目

校验算数加法:

import pytest

@pytest.mark.parametrize(

**"a,b,c"**,             # 参数名---多个参数

[(1, 2, 3),          # 参数值---参数值与参数对应,可传入多个需要校验的参数值

 (3, 4, 7),

 (5, 6, 11)]

)

def test_add(a, b, c):

       assert a+b == c

测试结果:

总结:

加法校验case中,传入了3组参数值,实际用例也运行了3次,每次取不同的数据。

九、跳过用例

当遇到不想运行的用例,可对该用例标记为跳过,在执行测试时,会自动跳转被标记的用例。使用

@pytest.mark.skip 标记跳过用例,使用@pytest.mark.xfail 标记用例时,则用例失败执行失败后,无任何错误信息。

下面的详细的用例代码:

test_skip_case.py

 import pytest

@pytest.mark.skip    # skip标记跳过用例,不执行
def test_add_1():

        assert 100 + 200 == 400, **"failed"**

@pytest.mark.skip
def test_add_2():

        assert 100 + 200 == 300, **"failed"**

 @pytest.mark.xfail   # xfail标记执行用例,但是不统计执行结果
 def test_add_3():

       assert 15 + 13 == 28, **"passed"**

 @pytest.mark.xfail
 def test_add_4():

      assert 15 + 13 == 100, **"failed"**

 def test_add_5():

      assert 3 + 2 == 5, **"passed"**

 def test_add_6():

       assert 3 + 2 == 6, **"failed"**

执行用例:pytest -v test_skip_case.py

[图片上传失败...(image-f7e8d5-1573551303032)]

可以看到,测试用例文件中,前两个用例未执行,第三、四个执行了,且第三个执行失败了,未收集失败信息。第五、第六个正常执行,第六个执行失败,显示具体的失败追踪信息。

十、生成测试报告

1、生成HTML格式的测试报告

生成html格式的测试报告,需要用例到插件pytest-html。具体步骤如下:

1)安装插件:pip install pytest-html

2)执行测试并生成测试报告:pytest -v -s --html=report.html

2、生成XML格式的测试报告

生成junit格式的xml报告,在命令行中加入--junit-xml=path 参数就可以了.

pytest -v --junit-xml=report.xml

十一、常见命令行参数

参考:
https://blog.csdn.net/lb245557472/article/details/90341297)
http://www.testclass.net/pytest
https://blog.csdn.net/crazyskady
http://pytest.org/en/latest/contents.html
https://www.bilibili.com/video/av59183665/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342