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的,有时间再来写

最新文章

  1. SQLserver技巧
  2. (转载)android炫酷实用的开源框架(UI框架)
  3. ReLU 和sigmoid 函数对比以及droupout
  4. MVC。Action方法,常用的返回类型有几种?
  5. UCloud可用区的设计理念及功能图文详解
  6. gradlew常用命令
  7. shell流程控制语句
  8. android:screenOrientation的说明 固定屏幕显示方向
  9. Tkinter教程之Canvas篇(1)
  10. 关于String字符串反转
  11. [BZOJ1385] [Baltic2000] Division expression (数学)
  12. beautiful soup
  13. Xposed 在android 6.0上报couldn&#39;t load class,找不到xposed_init中配置的入口类
  14. java io系列07之 FileInputStream和FileOutputStream
  15. Xpath在选择器中正确,在代码中返回的是空列表问题
  16. Tornado使用-队列Queue
  17. 译:微软发布.NET应用架构指南草案
  18. hibernate关联关系的crud2
  19. UITableView的UITableViewStyleGrouped
  20. MySql的数据查询

热门文章

  1. 【编程开发】CMake相关注意事项
  2. 使用 pycharm调试docker环境运行的Odoo
  3. JavaScript 短路值
  4. Golang中string和[]byte的对比
  5. idea查看源码没有注释的问题
  6. elasticsearch 的post put 方式的对比 setting mapping设置 - 添加查询数据
  7. 2019icpc南昌网络赛
  8. error: audit:backlog limit exceeded
  9. springboot+mybatis 用redis作二级缓存
  10. MySQL 按照日期格式查询带有时间戳数据