基于参数化夹具的Py.Test参数化

时间:2016-02-21 21:58:18

标签: python pytest

我有一个类范围的参数化夹具,它为其参数获取3个数据库并返回每个数据库的连接。

类中的测试使用此fixture来测试每个数据库连接属性。

现在我有一个带有数据库表测试的新类,我想使用上面的fixture,但要在每个连接表上进行参数化。

有关pytest实现此方法的任何建议吗?我无法找到一种基于已经参数化的元素进行参数化的方法。

由于

1 个答案:

答案 0 :(得分:2)

测试类用于:

  • 为测试用例提供设置和拆卸功能
  • 在测试期间分享一些共同的价值观

使用pytest这不是必需的,因为可以在夹具级别进行设置和拆卸。

出于这个原因,我的解决方案不使用类(但它可能与它们一起使用)。

要显示(假)连接已创建然后关闭,请在stdout上观察输出。诀窍是 使用@pytest.yield_fixturereturn但不使用yield来提供使用的值 参数注入测试用例。无论执行第一个yield语句后是什么 作为拆解代码。

"矩形"样式:M x N测试由两个参数化夹具

运行

第一种情况对于py.test是自然的,其中所有夹具变体都是组合的。

由于它有M×N测试用例运行,我称之为"矩形"。

我的测试位于tests/test_it.py

import pytest


@pytest.yield_fixture(scope="class", params=["mysql", "pgsql", "firebird"])
def db_connect(request):
    print("\nopening db")
    yield request.param
    print("closing db")


@pytest.fixture(scope="class", params=["user", "groups"])
def table_name(request):
    return request.param


def test_it(db_connect, table_name):
    print("Testing: {} + {}".format(db_connect, table_name))

如果您需要更多测试用例,例如test_it,只需使用其他名称创建它们。

运行我的测试用例::

$ py.test -sv tests
========================================= test session starts =========================================
platform linux2 -- Python 2.7.9 -- py-1.4.30 -- pytest-2.7.2 -- /home/javl/.virtualenvs/stack/bin/python2
rootdir: /home/javl/sandbox/stack/tests, inifile: 
collected 6 items 

tests/test_it.py::test_it[mysql-user] 
opening db
Testing: mysql + user
PASSEDclosing db

tests/test_it.py::test_it[pgsql-user] 
opening db
Testing: pgsql + user
PASSEDclosing db

tests/test_it.py::test_it[pgsql-groups] 
opening db
Testing: pgsql + groups
PASSEDclosing db

tests/test_it.py::test_it[mysql-groups] 
opening db
Testing: mysql + groups
PASSEDclosing db

tests/test_it.py::test_it[firebird-groups] 
opening db
Testing: firebird + groups
PASSEDclosing db

tests/test_it.py::test_it[firebird-user] 
opening db
Testing: firebird + user
PASSEDclosing db


====================================== 6 passed in 0.01 seconds =======================================

"爆炸三角形"从一个夹具到N个相关夹具

这个想法如下:

  • 使用parametrize fixture
  • 生成几个db_connect灯具
  • 为每个db_connect生成table_name fixtures
  • 的N个变体
  • test_it(db_connect, table_name)db_connect的正确组合调用table_name indirect

这根本不起作用

唯一的解决方案是使用某种明确定义哪种组合的场景 正确的。

"场景":测试功能级别的间接参数化

我们必须参数化测试功能,而不是参数化灯具。

通常,参数值按原样直接传递给测试函数。如果我们想要一个夹具(命名为 作为参数名称来处理创建要使用的值,我们必须指定参数 为indirect=True。如果我们说import pytest DBCFG = {"pgsql": "postgresql://scott:tiger@localhost:5432/mydatabaser", "mysql": "mysql://scott:tiger@localhost/foo", "oracle": "oracle://scott:tiger@127.0.0.1:1521/sidname" } @pytest.yield_fixture(scope="session") def db_connect(request): connect_name = request.param print("\nopening db {connect_name}".format(connect_name=connect_name)) assert connect_name in DBCFG yield DBCFG[connect_name] print("\nclosing db {connect_name}".format(connect_name=connect_name)) @pytest.fixture(scope="session") def table_name(request): return "tabname-by-fixture {request.param}".format(request=request) scenarios = [ ("mysql", "myslq-user"), ("mysql", "myslq-groups"), ("pgsql", "pgsql-user"), ("pgsql", "pgsql-groups"), ("oracle", "oracle-user"), ("oracle", "oracle-groups"), ] @pytest.mark.parametrize("db_connect,table_name", scenarios, indirect=["db_connect", "table_name"]) def test_it(db_connect, table_name): print("Testing: {} + {}".format(db_connect, table_name)) ,如果我们提供,所有参数都将以这种方式处理 参数名称列表,只有指定的参数将传递给夹具,剩下的将进入 因为他们正在进入测试功能。这里我使用间接参数的显式列表。

$ py.test -sv tests/test_indirect.py
py.test========================================= test session starts ==================================
=======
platform linux2 -- Python 2.7.9, pytest-2.8.7, py-1.4.31, pluggy-0.3.1 -- /home/javl/.virtualenvs/stack
/bin/python2
cachedir: tests/.cache
rootdir: /home/javl/sandbox/stack/tests, inifile:
collected 6 items

tests/test_indirect.py::test_it[mysql-myslq-user]
opening db mysql
Testing: mysql://scott:tiger@localhost/foo + tabname-by-fixture myslq-user
PASSED
closing db mysql

tests/test_indirect.py::test_it[mysql-myslq-groups]
opening db mysql
Testing: mysql://scott:tiger@localhost/foo + tabname-by-fixture myslq-groups
PASSED
closing db mysql

tests/test_indirect.py::test_it[pgsql-pgsql-user]
opening db pgsql
Testing: postgresql://scott:tiger@localhost:5432/mydatabaser + tabname-by-fixture pgsql-user
PASSED
closing db pgsql

tests/test_indirect.py::test_it[pgsql-pgsql-groups]
opening db pgsql
Testing: postgresql://scott:tiger@localhost:5432/mydatabaser + tabname-by-fixture pgsql-groups
PASSED
closing db pgsql

tests/test_indirect.py::test_it[oracle-oracle-user]
opening db oracle
Testing: oracle://scott:tiger@127.0.0.1:1521/sidname + tabname-by-fixture oracle-user
PASSED
closing db oracle

tests/test_indirect.py::test_it[oracle-oracle-groups]
opening db oracle
Testing: oracle://scott:tiger@127.0.0.1:1521/sidname + tabname-by-fixture oracle-groups
PASSED
closing db oracle


====================================== 6 passed in 0.01 seconds =======================================

运行测试套件:

db_connect

我们认为它有效。

无论如何,有一个小问题 - export class Base { private image: string = "img/dog.png"; // default image // you don't need catImg and dogImg here... // private catImg: string; // private dogImg: string; private currentImg: string; private enable: boolean; constructor() { } onMouseOver(image) { enable = true; currentImg = image; } onMouseClick(image) { enable = false; currentImg = image; } } 范围"会话"没有荣幸,事实确实如此 在功能级别实例化和销毁。这是known issue