pytest学习笔记---3

上一篇 / 下一篇  2020-07-25 15:30:39

接着上一篇的内容,这里主要讲下参数化,pytest很好的支持了测试函数中变量的参数化

一、pytest的参数化

1、通过命令行来实现参数化

  文档中给了一个简单的例子,

test_compute.py 的测试函数如下:
# content of test_compute.py
def test_compute(param1):
    assert param1<4

在conftest.py中添加两个函数,一个是添加参数,一个是根据参数生成测试

复制代码
# content of conftest.py
def pytest_addoption(parser):
    parser.addoption("--all", action="store_true",help="run all combinations")

def pytest_generate_tests(metafunc):if'param1'inmetafunc.fixturenames:ifmetafunc.config.option.all:    
            end=5else:
            end=2metafunc.parametrize("param1", range(end))
复制代码

通过在命令行添加--all的option来实现参数化,执行py.test -q test_compute.py 会发现只有2个case,而执行 py.test -q test_compute.py --all 会执行5个case

2、不同test IDs的参数化

   在pytest会为每一组参数集合建立一个ID,可以试用-k来select匹配的名字子串,所以可以为不同的测试数据建立ID来区分不同的case,这个是经常使用的变量参数化,注意pytest.mark.parametrize()的括号中的顺序,(变量名称,对应的(参数化元组)的数组,ID的数组) , 这样很好的解决了代码重复编写,减少了维护,可以很好的实现数据与代码想分离

复制代码
# content of test_time.py
import pytestfromdatetime import datetime, timedelta
testdata=[
(datetime(2001,12,12), datetime(2001,12,11), timedelta(1)),
(datetime(2001,12,11), datetime(2001,12,12), timedelta(-1)),
]
@pytest.mark.parametrize("a,b,expected", testdata)
def test_timedistance_v0(a, b, expected):
    diff= a -b
    assert diff==expected
@pytest.mark.parametrize("a,b,expected", testdata, ids=["forward","backward"])
def test_timedistance_v1(a, b, expected):
    diff= a -b
    assert diff== expected
复制代码

3、重要的资源参数化,这里面给了个case,是关于db的,觉得没太多可说的,就是一个简单的工厂,上代码了

复制代码
# content of conftest.py
import pytest
def pytest_generate_tests(metafunc):if'db'inmetafunc.fixturenames:
        metafunc.parametrize("db", ['d1','d2'], indirect=True)classDB1:"one database object"classDB2:"alternative database object"@pytest.fixture
def db(request):ifrequest.param =="d1":returnDB1()
    elif request.param=="d2":returnDB2()else:
        raise ValueError("invalid internal test config")
复制代码

4、通过类来实现测试函数的参数化,这个还是很有意义的,自己理解下吧,没什么难度

复制代码
# content of ./test_parametrize.py
import pytest
def pytest_generate_tests(metafunc):
    # called once per each test function
    funcarglist= metafunc.cls.params[metafunc.function.__name__]
    argnames= list(funcarglist[0])
    metafunc.parametrize(argnames, [[funcargs[name]fornameinargnames]forfuncargsinfuncarglist])classTestClass:
    # a map specifying multiple argument setsfora test methodparams={'test_equals': [dict(a=1, b=2), dict(a=3, b=3), ],'test_zerodivision': [dict(a=1, b=0), ],
    }
  def test_equals(self, a, b):
      assert a==b
  def test_zerodivision(self, a, b):
      pytest.raises(ZeroDivisionError,"a/b")
复制代码

5、通过multiple fixtures来实现间接的参数化,文档中给了使用不同版本的python编译器的代码,有需求的自己看下吧

复制代码
"""module containing a parametrized tests testing cross-python
serialization via the pickle module."""import py
import pytest
import _pytest._code
pythonlist= ['python2.6','python2.7','python3.3']
@pytest.fixture(params=pythonlist)
def python1(request, tmpdir):
    picklefile= tmpdir.join("data.pickle")returnPython(request.param, picklefile)
@pytest.fixture(params=pythonlist)
def python2(request, python1):returnPython(request.param, python1.picklefile)classPython:
    def __init__(self, version, picklefile):
        self.pythonpath=py.path.local.sysfind(version)ifnot self.pythonpath:
            pytest.skip("%r not found"%(version,))
        self.picklefile=picklefile
    def dumps(self, obj):
        dumpfile= self.picklefile.dirpath("dump.py")
        dumpfile.write(_pytest._code.Source("""import pickle
            f= open(%r,'wb')
            s= pickle.dump(%r, f, protocol=2)
            f.close()"""% (str(self.picklefile), obj)))py.process.cmdexec("%s %s"%(self.pythonpath, dumpfile))
    def load_and_is_true(self, expression):
        loadfile= self.picklefile.dirpath("load.py")
        loadfile.write(_pytest._code.Source("""import pickle
            f= open(%r,'rb')
            obj=pickle.load(f)
            f.close()
            res= eval(%r)ifnot res:
            raise SystemExit(1)"""% (str(self.picklefile), expression)))print (loadfile)
        py.process.cmdexec("%s %s"%(self.pythonpath, loadfile))
@pytest.mark.parametrize("obj", [42, {}, {1:3},])
def test_basic_objects(python1, python2, obj):
    python1.dumps(obj)
    python2.load_and_is_true("obj == %s"% obj)
复制代码

二、使用自定义的markers

1、自定义一个mark,如下,然后 py.test -v -m webtest 只运行标记了webtest的函数, py.test -v -m "not webtest"  来运行未标记webtest的

复制代码
# content of test_server.py
import pytest
@pytest.mark.webtest
def test_send_http():
    pass # perform. some webtest testforyour app
def test_something_quick():
    pass
def test_another():
    passclassTestClass:
    def test_method(self):
        pass
复制代码

2、还可以通过-v 指定的函数ID, py.test -v test_server.py::TestClass::test_method 来运行指定的函数

3、使用-k 来匹配名字子串, py.test -v -k http , py.test -k "not send_http" -v

4、在pytest.ini中**markers

# content of pytest.ini
[pytest]
markers=webtest: mark a testasa webtest.
    addopts= --pyargs

好了,就这么多吧,下面的一些关于mocking的,有时间再来写


TAG:

 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

我的栏目

日历

« 2020-08-11  
      1
2345678
9101112131415
16171819202122
23242526272829
3031     

数据统计

  • 访问量: 2348
  • 日志数: 115
  • 建立时间: 2020-06-02
  • 更新时间: 2020-08-11

RSS订阅

Open Toolbar