zoukankan      html  css  js  c++  java
  • pytest的使用

    一、python安装

    1.windows(server):

    双击python-3.6.7-amd64.exe执行安装流程,使用默认安装方式即可。

    安装完成后查看是否安装成功:

    C:UsersAdministrator>python --version

    'python' is not recognized as an internal or external command,

    operable program or batch file.

    如果出现不识别python的情况,需要将python的安装路径添加到环境变量,computer->properties->enviroment variables,

    找到Path变量,将python的安装路径和安装路径下的Scripts目录加在后面。

    比如:

    C:UsersAdministratorAppDataLocalProgramsPythonPython36;C:UsersAdministratorAppDataLocalProgramsPythonPython36Scripts

    重新打开cmd窗口,再次查看python版本,

    C:UsersAdministrator>python --version

    Python 3.6.7

    安装成功

    2.linux:

    # tar -xJf Python-3.6.7.tar.xz

    # cd Python-3.6.7/

    # ./configure --prefix=/usr/local/python --enable-shared CFLAGS=-fPIC

    # make

    # make install

    安装完成后,查看python版本还是2.7, # python --version

    python 2.7.13

    这是因为在/usr/bin下的python是一个指向python2.7的软连接,需要手工调整下:

    # ls -l /usr/bin/python

    lrwxrwxrwx 1 root root 9 Dec  6  2017 /usr/bin/python -> python2.7

    # rm /usr/bin/python

    # ln -s /usr/local/python/bin/python3.6 /usr/bin/python

    后续如果用到其他的软件必须使用2.7的情况时可以用同样的方法切回来

    这时候再check下python的版本情况:

    # python --version

    python: error while loading shared libraries: libpython3.6m.so.1.0: cannot open shared object file: No such file or directory

    提示找不到libpython3.6m.so.1.0,那是因为之前编译出来的so文件安装在了/usr/local/python/lib,需要将这个路径加到系统的so搜索路径中:

    将路径增加到/etc/ld.so.conf文件中

    # cat /etc/ld.so.conf

    /usr/local/lib64

    /usr/local/lib

    /usr/local/python/lib/

    include /etc/ld.so.conf.d/*.conf

    # ldconfig

    再次check安装已经完成:

    # python --version

    Python 3.6.7

    备注:

    Python安装过程中会依赖zlib,部分linux版本没有zlib需要自行安装,安装方法如下:

    cd zlib-1.2.8/

    ./configure

    Make && make install

    二、pip安装

    1.windows(server):

    在C:Users用户名pip 目录(如果没有就新建一个)下添加pip.ini 文件,然后编辑其内容如下(配置这个的目的是使用pip install下载安装服务器上的支撑库包,如果使用pip自带库默认设置即可):
    [global]
    trusted-host=pip ftp服务器地址
    index-url=http://pip ftp服务器地址/simple/

    配置完成打开cmd,使用pip install检查pip是否可用,C:UsersAdministrator>pip install setuptools-scm

    pip安装完成后安装pycharm ide开发工具,从pycharm官网或者附件中下载pycharm安装包,双击安装,安装过程中需要注意的步骤如下:

    注意:

    (1)安装过程勾选add lanchers dir to the PATH

    (2)安装完成后就可以使用了,首先创建一个工程,可以将工程创建在已下载的测试脚本目录中,新建一个工程后,左上角file->Setting->Tools->Python Integrated Tools-> Default test runner->选择pytest

    2.linux:

    pip源码传到linux。

    # cd pip-18.1

    # python setup.py install

    # ln -s /usr/local/python/bin/pip /usr/local/bin/pip

    # pip --version

    pip 18.1 from /usr/local/python/lib/python3.6/site-packages/pip-18.1-py3.6.egg/pip (python 3.6)

    安装完成后需要配置下pip服务器(配置这个的目的是使用pip install下载安装服务器上的支撑库包,如果使用pip自带库默认设置即可):

    编辑~/.pip/目录下的pip.conf文件(如果没有则创建该文件~/.pip/pip.conf),然后编辑其内容如下
    [global]
    trusted-host=pip ftp服务器地址
    index-url=http://pip ftp服务器地址/simple/

    三、安装pytest依赖库

    pip install pytest

    pip install pytest-html

    pip install paramiko

    pip install rpyc

    pip install request

    四、使用pytest

    1.配置文件

    pytest.ini是pytest的主配置文件,可以改变pytest的默认行为,按指定的方式去运行。Pytest.ini的基本格式:

    # 保存为pytest.ini文件

    [pytest]

    addopts = -rsxX

    pytest.ini可以放在测试脚本的目录中或者通过pytest调用时的命令行参数指定:

    pytest  -c "E:Desktoppytest_local.ini"

    不推荐使用命令行参数指定的方式,因为使用-c参数后,原来在测试脚本根目录中的pytest.ini就默认不使能了,pytest就会使用当前文件夹作为rootdir,破坏了一般意义上我们测试脚本的根目录是pytest.ini所在目录的固定观念。当然,我们可以通过制定命令行参数---rootdir来指定运行根目录:

    testcasedir_level1dir_level2>pytest -c "E:Desktoppytest_local.ini" --rootdir="E:DesktopSublime Text Build_x64 est_ini"

    pytest确定rootdir的方法见手册:

    https://docs.pytest.org/en/latest/customize.html#initialization-determining-rootdir-and-inifile

    2.配置项

    本节会介绍我们常用的配置项,对于其他的配置项,请在官方手册中查询。

    adopts

    addopts参数可以更改默认命令行选项,等同于我们在cmd输入指令去执行用例的时候加的参数,比如指定测试床信息和生成的日志文件目录:

    [pytest]

    addopts = --testbed="E:Desktop opology_template.yaml" --reportpath="E:Desktop"

    --testbed

    用于指定测试床的命令行参数,可以写入addopts中或者在调用的时候手动输出,该参数必选。

    --reportpath

    用于指定生成日志文件的根目录,如果不选,日志文件会默认选择pytest的rootdir作为日志的根目录

    python_functions

    匹配测试用例编号,用例编号一般都是有固定开头的,比如以TestCase_开头,因此配置为TestCase_

    python_files

    匹配测试脚本文件名,TestCase的脚本名都是TestCase_开头的,因此配置为TestCase_*

    综上,我们在子系统根目录下放置的pytest.ini样例如下,脚本运行时可以根据自己的需要修改。

    # pytest.ini

    [pytest]

    addopts = -s --testbed="E:Desktop opology_template.yaml" --reportpath="E:Desktop"

    python_files = TestCase_*

    python_functions = TestCase_*

    下面介绍部分常用配置项

    markers

    为了避免自定义标记的拼写错误,可以通过makers字段在pytest.ini文件中注册标记,如有不在markers字段中的标记,pytest运行时会报错。

    [pytest]

    markers =

    smoke: run smoke testcase

    func: run functionarity testcase

    标记注册好之后,可以通过pytest --makers来查看

    五、脚本写作

    1.执行单个测试用例

    创建一个.py文件(test_001.py),对个简单的功能进行测试。

    #coding=utf-8

    # 方法

    def func(x):

        return x + 1

    # 测试用例

    def test_answer():

        assert func(3) == 5

    注意:测试用例函数命名应全部小写,并以test_开头,如test_answer

    切换到测试文件所在的目录,通过“pytest”命令运行测试

    c:python_ts>pytest

    2.执行多个测试用例

    在一个测试类中可以创建多个测试用例:

    #coding=utf-8

    class TestClass:

        def test_one(self):

            x = "this"

            assert "h" in x

        def test_two(self):

            x = "hello"

            assert x == "hi"

    注意:测试类命名规范为以Test开头

    pytest指定文件运行:

    >pytest -q test_002.py

    -q  为quiet。表示在安静的模式输出报告。-q 不会输出pytest的版本信息。

    如果没有参数,pytest会查看当前目录和所有子目录的测试文件(test_开头或者

    _test结尾)并运行。 也可以指定文件名,目录名称或这些名称的列表。

    发现规则小结

    •  测试文件应该命名为test_.py 或_test.py

    •  测试方法和函数应该被命名为test_。

    •  测试类应该被命名为Test

    结果类型:

    以下是测试功能的几种常见的结果:

    •  PASSED (.):测试成功。

    •  FAILED (F): 测试失败。

    •  ERROR (E):错误

    3.从python代码中调用pytest

    通过python代码执行pytest

    (1)直接执行pytest.main() 【自动查找当前目录下,以test_开头的文件或者以_test结尾的py文件】

    (2)设置pytest的执行参数 pytest.main(['--html=./report.html','test_xxx.py'])【执行test_login.py文件,并生成html格式的报告】

    方式2中,pytest.main()的参数其实是个list,执行参数和插件参数,多个参数时[]内的多个参数通过‘逗号,’进行分割

    比如,在C:python_testscript目录下有三个py文件

    python_testscript/

    ├── test_001.py

    ├── test_002.py

    └── test_003.py

    其中test_003.py的代码如下:

    import pytest

    def test_main():

        assert 5 != 5

    if __name__ == '__main__':

        pytest.main()

    pytest.main不带参数,直接运行该程序,sublime 中按Ctrl+B 运行。结果如下:

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

    platform win32 -- Python 3.7.1, pytest-4.0.2, py-1.7.0, pluggy-0.8.0

    rootdir: C:python_testscript, inifile:

    plugins: metadata-1.7.0, html-1.19.0

    collected 4 items

    test_001.py F                                                            [ 25%]

    test_002.py .F                                                            [ 75%]

    test_003.py F                                                            [100%]

    ================================== FAILURES ===================================

    _________________________________ test_answer _________________________________

        def test_answer():

    >       assert func(3) == 5

    E       assert 4 == 5

    E        +  where 4 = func(3)

    test_001.py:9: AssertionError

    _____________________________ TestClass.test_two ______________________________

    self = <test_002.TestClass object at 0x0000000003791A90>

        def test_two(self):

            x = "hello"

    >       assert x == "hi"

    E       AssertionError: assert 'hello' == 'hi'

    E         - hello

    E         + hi

    test_002.py:11: AssertionError

    __________________________________ test_main __________________________________

        def test_main():

    >       assert 5 != 5

    E       assert 5 != 5

    test_003.py:4: AssertionError

    ===================== 3 failed, 1 passed in 0.22 seconds ======================

    [Finished in 1.4s]

    从执行结果看到,main() 默认执行了当前文件所在的目录下的所有测试文件。

    那么,如果我们只想运行某个测试文件呢?可以向main()中添加参数:

    import pytest

    def test_main():

        assert 5 != 5

    if __name__ == '__main__':

        pytest.main(['test_001.py'])

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

    platform win32 -- Python 3.7.1, pytest-4.0.2, py-1.7.0, pluggy-0.8.0

    rootdir: C:python_testscript, inifile:

    plugins: metadata-1.7.0, html-1.19.0

    collected 1 item

    test_001.py F                                                            [100%]

    ================================== FAILURES ===================================

    _________________________________ test_answer _________________________________

        def test_answer():

    >       assert func(3) == 5

    E       assert 4 == 5

    E        +  where 4 = func(3)

    test_001.py:9: AssertionError

    ========================== 1 failed in 0.06 seconds ===========================

    [Finished in 1.2s]

    4.常用参数说明

    (1)执行失败N条用例后停止运行

    pytest -x # 第一条用例失败后停止运行

    pytest --maxfail=2 # 失败两条用例后停止运行

    (2) 指定执行用例

    pytest test_abc.py # 执行test_abc.py中的所有用例

    pytest testing/ # 执行testing目录下的所有用例

    pytest test_abc.py::TestClassA::test_sample # 执行test_abc.py文件中的TestClassA测试类中的test_sample方法

    pytest -v -m AR161 # 按标签执行当前目录下,fixture为AR1610的用例

    (3)循环执行用例

    pytest --count 30 # 带--count参数指定循环次数(需要安装pytest-repeat包)

    (4) 生成测试报告

    pytest --junitxml=path # 生成junit类型测试报告

    pytest -v --html=testresult.html # 生成html类型测试报告

    (5) cmd命令行执行过程打印信息

    pytest --capture=no

    (6)其他参数

    pytest –v  #输出详细信息

    pytest –q  #静默模式,不输出python的版本信息等

    5.常用断言和异常处理

    (1)常用断言:

    assert a==b,”添加断言备注信息”

    assert a!=b, ”添加断言备注信息”

    assert a, ”添加断言备注信息”

    assert not a, ”添加断言备注信息”

    assert “abc” in “123abc” , ”添加断言备注信息”

    assert “ef” not in “123abc” , ”添加断言备注信息

    (2)python的标准异常

    异常名称         描述

    BaseException 所有异常的基类

    SystemExit       解释器请求退出

    KeyboardInterrupt  用户中断执行(通常是输入^C)

    Exception 常规错误的基类

    StopIteration   迭代器没有更多的值

    GeneratorExit 生成器(generator)发生异常来通知退出

    StandardError 所有的内建标准异常的基类

    ArithmeticError        所有数值计算错误的基类

    FloatingPointError   浮点计算错误

    OverflowError 数值运算超出最大限制

    ZeroDivisionError    除(或取模)零 (所有数据类型)

    AssertionError 断言语句失败

    AttributeError 对象没有这个属性

    EOFError  没有内建输入,到达EOF 标记

    EnvironmentError    操作系统错误的基类

    IOError     输入/输出操作失败

    OSError    操作系统错误

    WindowsError 系统调用失败

    ImportError     导入模块/对象失败

    LookupError     无效数据查询的基类

    IndexError        序列中没有此索引(index)

    KeyError  映射中没有这个键

    MemoryError  内存溢出错误(对于Python 解释器不是致命的)

    NameError       未声明/初始化对象 (没有属性)

    UnboundLocalError 访问未初始化的本地变量

    ReferenceError        弱引用(Weak reference)试图访问已经垃圾回收了的对象

    RuntimeError  一般的运行时错误

    NotImplementedError     尚未实现的方法

    SyntaxError      Python 语法错误

    IndentationError      缩进错误

    TabError  Tab 和空格混用

    SystemError     一般的解释器系统错误

    TypeError 对类型无效的操作

    ValueError        传入无效的参数

    UnicodeError   Unicode 相关的错误

    UnicodeDecodeError       Unicode 解码时的错误

    UnicodeEncodeError        Unicode 编码时错误

    UnicodeTranslateError    Unicode 转换时错误

    Warning   警告的基类

    DeprecationWarning       关于被弃用的特征的警告

    FutureWarning         关于构造将来语义会有改变的警告

    OverflowWarning    旧的关于自动提升为长整型(long)的警告

    PendingDeprecationWarning  关于特性将会被废弃的警告

    RuntimeWarning     可疑的运行时行为(runtime behavior)的警告

    SyntaxWarning         可疑的语法的警告

    UserWarning   用户代码生成的警告

    (3)异常处理

    1)try...except

    a=10

    b=0

    try:

        c=a/b

    except:

        print("error")

    print("done")

    2)try ....except...else 语句,当没有异常发生时,else中的语句将会被执行

    a=10

    b=0

    try:

        c = b/ a

    except:

        print("error")

    else:

        print("no error")

    print("done")

    3)raise 引发一个异常

    inputValue=input("please input a int data :")

    if type(inputValue)!=type(1):

        raise ValueError

    else:

        print(inputValue)

    4)try ...finally ,无论异常是否发生,在程序结束前,finally中的语句都会被执行

    a=10

    b=0

    try:

        c = a/ b

    finally:

        print("always excute")

    finally语句也可以和except语句一起使用

    a=10

    b=0

    try:

        c = a/ b

    except:

        print("error")

    finally:

        print("always excute")

    6.正则表达式

    必须要import re

    1) re.match函数

    re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。

    如:

    import re

    print(re.match('www', 'www.123.com') .group())    # 在起始位置匹配

    print(re.match('com', 'www.123.com'))         # 不在起始位置匹配

    输出结果:

    www

    None

    2)re.search方法

    re.search 扫描整个字符串并返回第一个成功的匹配。

    如:

    import re

    print(re.search('www', 'www.123.com').group()) 

    print(re.search('com', 'www.123.com').group())

    输出结果:

    www

    com

    re.match与re.search的区别:

    re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。

    3) re.findall函数

    在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。

    注意: match 和 search 是匹配一次 ,findall 匹配所有。

    import re

    print(re.finditer(r"d+","12a32bc43de3")) 

    输出结果:

    ['12', '32', '43', '3']

    4) re. finditer函数

    和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。

    import re

    it = re.finditer(r"d+","12a32bc43de3")

    for match in it:

        print (match.group() )

    输出结果:

    12

    32

    43

    3

    六、测试套特性目录内容举例

    1.测试套即为特性目录名,如testcase/startup,特性目录下存放__init__.py、conftest.py以及requirements.py及测试用例脚本文件

    1)__init__.py :为空文件即可,标识该目录为一个package

    2)contest.py:  定义脚本的setup和teardown,结构如下:

    # --------------------------------------------------------

    #注释部分

    # --------------------------------------------------------

    #依赖的模块

    import os,sys
    sys.path.append(os.path.split(os.path.realpath(__file__))[0])
    from requirements import *

    @pytest.fixture(scope='package', autouse=True)
    def testuite_setup_teardown():

    #准备工作:每个特性的所有用例执行前执行一次
    Log.log(' ------------testsuite setup begin--------------')
    dta.login()


    yield

    #环境清理:每个特性所有用例执行完执行一次
    Log.log(' ------------testsuite teardown begin--------------')

    @pytest.fixture(scope='function', autouse=True)
    def testcase_setup_teardown():

    #准备工作:每个用例运行前执行一次
    Log.log(' ------------testcase setup begin--------------')
    yield

    #环境清理:每个用例运行完执行一次
    Log.log(' ------------testcase teardown begin--------------')

    3)requirements.py :存放所有需要依赖的模块

    ######################系统模块##########################
    import time
    import datetime
    import re
    import pytest
    import sys
    import os
    from ctypes import *

    ######################pytest_testlib_base模块##########################
    import Log
    import rpyc_client
    import rpyc_server

    ######################本地自定义common模块##########################
    sys.path.append("%s/../../common/"%(os.path.split(os.path.realpath(__file__))[0]))
    sys.path.append("%s/../../common/STARTUP"%(os.path.split(os.path.realpath(__file__))[0]))
    import py_base
    import file_method

    4)测试用例脚本文件:

    # --------------------------------------------------------

    #
    #--
    # 用例编号 : TESTCASE_1001
    # 用例名称 :测试用例demo
    # --------------------------------------------------------

    from requirements import *

    @pytest.fixture(scope='function', autouse=True)
    def prepare_cleanup():
    Log.log(' ------------prepare begin--------------')
    yield
    Log.log(' ------------cleanup begin--------------')

    def  TESTCASE_1001(): 

           Log.log("操作步骤1、设备启动,有预期结果1")

           #py_base.py文件及check_startup方法定义在整个工程目录中common文件夹中,通过requirements.py 的本地自定义common模块声明引入

           py_base.check_startup(dev_a)

           Log.log("预期结果1、设备正常启动")

  • 相关阅读:
    C语言基础10
    swift笔记06
    C语言基础09
    C语言基础08
    C语言基础07
    C语言基础06
    swift笔记05
    Swift笔记4
    C语言基础05
    [转]一个清华计算机博士生的退学申请
  • 原文地址:https://www.cnblogs.com/alphain/p/10855884.html
Copyright © 2011-2022 走看看