• pytest学习笔记(三)


    接着上一篇的内容,这里主要讲下参数化,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' in metafunc.fixturenames:
            if metafunc.config.option.all:    
                end = 5
            else:
                end = 2
            metafunc.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 pytest
    from datetime 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' in metafunc.fixturenames:
            metafunc.parametrize("db", ['d1', 'd2'], indirect=True)
    class DB1:
        "one database object"
    class DB2:
        "alternative database object"
    @pytest.fixture
    def db(request):
        if request.param == "d1":
            return DB1()
        elif request.param == "d2":
            return DB2()
        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] for name in argnames] for funcargs in funcarglist])
    class TestClass:
        # a map specifying multiple argument sets for a test method
        params = {
            '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")
        return Python(request.param, picklefile)
    @pytest.fixture(params=pythonlist)
    def python2(request, python1):
        return Python(request.param, python1.picklefile)
    class Python:
        def __init__(self, version, picklefile):
            self.pythonpath = py.path.local.sysfind(version)
            if not 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)
                if not 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 test for your app
    def test_something_quick():
        pass
    def test_another():
        pass
    class TestClass:
        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 test as a webtest.
        addopts = --pyargs

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

  • 相关阅读:
    Kettle 使用入门
    git mac客户端使用提交与同步
    MAC 远程桌面链接 证书或链接无效
    mac下wifi无法连接的问题
    mysql时间段内查询
    mybatis 特殊符号及like的使用
    mac下剪切文件或文件夹
    eclipse下使用git下载和上传项目
    unbutu下搭建FTP服务
    mybatis 的if else
  • 原文地址:https://www.cnblogs.com/sparkling-ly/p/5708575.html
Copyright © 2020-2023  润新知