每次迭代的 pytest 新测试 |循环 |参数化夹具
pytest new test for every iteration | for loop | parametrize fixture
基本上,我正在尝试对路由列表的每次迭代进行测试,以检查与特定功能关联的网页 return 是否具有有效的状态代码。
我想要类似这样的东西:
import pytest
from flask import url_for
from myflaskapp import get_app
@pytest.yield_fixture
def app():
# App context and specific overrides for test env
yield get_app()
@pytest.yield_fixture
def client(app):
yield app.test_client()
@pytest.yield_fixture
def routes(app):
routes = [
'foo',
'bar',
# There's quite a lot of function names here
]
with app.app_context():
for n, route in enumerate(routes):
routes[n] = url_for(route)
# yield url_for(route) #NOTE: This would be ideal, but not allowed.
# convert the routes from func names to actual routes
yield routes
@pytest.mark.parametrize('route', routes)
def test_page_load(client, route):
assert client.get(route.endpoint).status_code == 200
我读到你不能将参数化与夹具混合作为参数,因为类似于 interpretation/load/execution 顺序,但是,如何根据 'best practice' 解决这个问题?
我看到了一个解决方案,您可以直接从函数生成测试,这看起来非常灵活,可能符合我的要求 (虽然我不能使用调用固定装置装饰直接运行,所以可能不是)
不过,我是 pytest 的新手,我很想看到更多示例,了解如何在几乎没有限制的情况下在迭代中生成测试或执行多个测试,同时遵守正确的 pytest 样式和 DRY原则。 (我知道 conftest.py)
如果重要的话,我会优先考虑 versatility/practicality 而不是适当的样式。 (在某种程度上,可维护性也是一个高优先级)
我希望能够参考这个问题的解决方案,以帮助指导我将来如何构建我的测试,但我似乎一直在点击 roadblocks/limitations 或被 pytest 告知我不能像我一样做 X 解决方案 expect/want。
相关帖子:
- 干燥:
- 从函数生成测试:
- 非常简单的解决方案(不适用于这种情况):Parametrize pytest fixture
- PyTest 中的 Flask 应用上下文:Testing code that requires a Flask app or request context
- 使用多个列表固定装置避免边缘情况:
我目前摸索出的解决方案是这样的:
import pytest
from flask import url_for
from myflaskapp import get_app
@pytest.fixture
def app():
app = get_app()
# app context stuff trimmed out here
return app
@pytest.fixture
def client(app):
client = app.test_client()
return client
def routes(app):
'''GET method urls that we want to perform mass testing on'''
routes = ['foo', 'bar']
with app.app_context():
for n, route in enumerate(routes):
routes[n] = url_for(route)
return routes
@pytest.mark.parametrize('route', routes(get_app()))
#NOTE: It'd be really nice if I could use routes as a
# fixture and pytest would handle this for me. I feel like I'm
# breaking the rules here doing it this way. (But I don't think I actually am)
def test_page_load(client, route):
assert client.get(route.endpoint).status_code == 200
我对这个解决方案的最大问题是,我不能直接将夹具作为函数调用,而这个解决方案要么需要这样做,要么在夹具外部完成我的夹具所做的所有工作,这并不理想.我希望能够参考此解决方案来解决我将来如何构建测试的问题。
对于任何想专门复制我的 FLASK 解决方案的人:
我目前的解决方案对某些人来说可能比对我来说更糟糕,我为我的 get_app()
使用单例结构,所以如果 get_app()
在我的情况下被多次调用应该没问题,因为如果尚未定义全局变量,它将调用 create_app()
并将应用程序本身存储为全局变量,基本上模拟仅调用 create_app()
一次的行为。
Pytest 装置本身可以参数化,但不能使用 pytest.mark.parametrize
。 (貌似这种问题也有人回答了here。)所以:
import pytest
from flask import url_for
from myflaskapp import get_app
@pytest.fixture
def app():
app = get_app()
# app context stuff trimmed out here
return app
@pytest.fixture
def client(app):
client = app.test_client()
return client
@pytest.fixture(params=[
'foo',
'bar'
])
def route(request, app):
'''GET method urls that we want to perform mass testing on'''
with app.app_context():
return url_for(request.param)
def test_page_load(client, route):
assert client.get(route.endpoint).status_code == 200
The documentation 是这样解释的:
Fixture functions can be parametrized in which case they will be called multiple times, each time executing the set of dependent tests, i. e. the tests that depend on this fixture. Test functions usually do not need to be aware of their re-running. Fixture parametrization helps to write exhaustive functional tests for components which themselves can be configured in multiple ways.
Extending the previous example, we can flag the fixture to create two smtp_connection fixture instances which will cause all tests using the fixture to run twice. The fixture function gets access to each parameter through the special request object:
# content of conftest.py
import pytest import smtplib
@pytest.fixture(scope="module", params=["smtp.gmail.com", "mail.python.org"])
def smtp_connection(request):
smtp_connection = smtplib.SMTP(request.param, 587, timeout=5)
yield smtp_connection
print("finalizing {}".format(smtp_connection))
smtp_connection.close()
The main change is the declaration of params with @pytest.fixture, a list of values for each of which the fixture function will execute and can access a value via request.param. No test function code needs to change.
基本上,我正在尝试对路由列表的每次迭代进行测试,以检查与特定功能关联的网页 return 是否具有有效的状态代码。
我想要类似这样的东西:
import pytest
from flask import url_for
from myflaskapp import get_app
@pytest.yield_fixture
def app():
# App context and specific overrides for test env
yield get_app()
@pytest.yield_fixture
def client(app):
yield app.test_client()
@pytest.yield_fixture
def routes(app):
routes = [
'foo',
'bar',
# There's quite a lot of function names here
]
with app.app_context():
for n, route in enumerate(routes):
routes[n] = url_for(route)
# yield url_for(route) #NOTE: This would be ideal, but not allowed.
# convert the routes from func names to actual routes
yield routes
@pytest.mark.parametrize('route', routes)
def test_page_load(client, route):
assert client.get(route.endpoint).status_code == 200
我读到你不能将参数化与夹具混合作为参数,因为类似于 interpretation/load/execution 顺序,但是,如何根据 'best practice' 解决这个问题?
我看到了一个解决方案,您可以直接从函数生成测试,这看起来非常灵活,可能符合我的要求
不过,我是 pytest 的新手,我很想看到更多示例,了解如何在几乎没有限制的情况下在迭代中生成测试或执行多个测试,同时遵守正确的 pytest 样式和 DRY原则。 (我知道 conftest.py)
如果重要的话,我会优先考虑 versatility/practicality 而不是适当的样式。 (在某种程度上,可维护性也是一个高优先级)
我希望能够参考这个问题的解决方案,以帮助指导我将来如何构建我的测试,但我似乎一直在点击 roadblocks/limitations 或被 pytest 告知我不能像我一样做 X 解决方案 expect/want。
相关帖子:
- 干燥:
- 从函数生成测试:
- 非常简单的解决方案(不适用于这种情况):Parametrize pytest fixture
- PyTest 中的 Flask 应用上下文:Testing code that requires a Flask app or request context
- 使用多个列表固定装置避免边缘情况:
我目前摸索出的解决方案是这样的:
import pytest
from flask import url_for
from myflaskapp import get_app
@pytest.fixture
def app():
app = get_app()
# app context stuff trimmed out here
return app
@pytest.fixture
def client(app):
client = app.test_client()
return client
def routes(app):
'''GET method urls that we want to perform mass testing on'''
routes = ['foo', 'bar']
with app.app_context():
for n, route in enumerate(routes):
routes[n] = url_for(route)
return routes
@pytest.mark.parametrize('route', routes(get_app()))
#NOTE: It'd be really nice if I could use routes as a
# fixture and pytest would handle this for me. I feel like I'm
# breaking the rules here doing it this way. (But I don't think I actually am)
def test_page_load(client, route):
assert client.get(route.endpoint).status_code == 200
我对这个解决方案的最大问题是,我不能直接将夹具作为函数调用,而这个解决方案要么需要这样做,要么在夹具外部完成我的夹具所做的所有工作,这并不理想.我希望能够参考此解决方案来解决我将来如何构建测试的问题。
对于任何想专门复制我的 FLASK 解决方案的人:
我目前的解决方案对某些人来说可能比对我来说更糟糕,我为我的 get_app()
使用单例结构,所以如果 get_app()
在我的情况下被多次调用应该没问题,因为如果尚未定义全局变量,它将调用 create_app()
并将应用程序本身存储为全局变量,基本上模拟仅调用 create_app()
一次的行为。
Pytest 装置本身可以参数化,但不能使用 pytest.mark.parametrize
。 (貌似这种问题也有人回答了here。)所以:
import pytest
from flask import url_for
from myflaskapp import get_app
@pytest.fixture
def app():
app = get_app()
# app context stuff trimmed out here
return app
@pytest.fixture
def client(app):
client = app.test_client()
return client
@pytest.fixture(params=[
'foo',
'bar'
])
def route(request, app):
'''GET method urls that we want to perform mass testing on'''
with app.app_context():
return url_for(request.param)
def test_page_load(client, route):
assert client.get(route.endpoint).status_code == 200
The documentation 是这样解释的:
Fixture functions can be parametrized in which case they will be called multiple times, each time executing the set of dependent tests, i. e. the tests that depend on this fixture. Test functions usually do not need to be aware of their re-running. Fixture parametrization helps to write exhaustive functional tests for components which themselves can be configured in multiple ways.
Extending the previous example, we can flag the fixture to create two smtp_connection fixture instances which will cause all tests using the fixture to run twice. The fixture function gets access to each parameter through the special request object:
# content of conftest.py import pytest import smtplib @pytest.fixture(scope="module", params=["smtp.gmail.com", "mail.python.org"]) def smtp_connection(request): smtp_connection = smtplib.SMTP(request.param, 587, timeout=5) yield smtp_connection print("finalizing {}".format(smtp_connection)) smtp_connection.close()
The main change is the declaration of params with @pytest.fixture, a list of values for each of which the fixture function will execute and can access a value via request.param. No test function code needs to change.