从pytest断言中解析出数据并转换成字符串
Parsing out data from pytest assert and converting into a string
我想将有关测试的数据收集到外部数据库,我将在其中收集所有断言并解析预期值与实际结果。
在代码中描述我想要的东西:
test_something.py:
def test_me_1(send_to_test):
"""
Docstring to pad even more
"""
x,y = send_to_test(3)
assert x == 3**2
assert y == 3**3
assert y == 3**2 # I want this to fail intentionally
conftest.py:
@pytest.fixture(scope='function')
def send_to_test() -> Callable:
return lambda x: (x ** 2, x ** 3)
我要收集的数据是(其他任何方式都可以,只要我得到这个数据):
test_data = [{'func': 'test_me_1', 'variable': 'x', 'expected_value': 9, 'actual_value': 9},
{'func': 'test_me_1', 'variable': 'y', 'expected_value': 27, 'actual_value': 27},
{'func': 'test_me_1', 'variable': 'y', 'expected_value': 27, 'actual_value': 9}]
我目前的想法是一个包装器,它可以很容易地实现到现有的测试中,并将收集断言语句及其值。
如果我使用 AST,收集 assert 语句的数量很简单,但这些仅适用于静态分析。
我也尝试过使用 inspect 模块,但很难弄清楚如何为此目的使用它
到目前为止我的失败尝试(打印语句是临时的,因为我想收集数据)
def get_this(func: Callable):
@functools.wraps(func)
def wrapper(*arg, **kwargs):
print(func.__name__)
func_content = inspect.getsource(func)
func_root = ast.parse(func_content)
for node in func_root.body:
for content in node.body:
if isinstance(content, ast.Assert):
print(content)
return func(*arg, **kwargs)
return wrapper
你可以试试这个:
import inspect
import json
from typing import Callable
import pytest
@pytest.fixture(scope="function")
def send_to_test() -> Callable:
return lambda x: (x ** 2, x ** 3)
# Helper function to run and monitor a test
def run_test(test_func, variable, expected_value, actual_value, data):
try:
with open("./data.json", "r") as f:
data = json.load(f)
except FileNotFoundError:
data = []
data.append(
{
"func": test_func,
"variable": variable,
"expected_value": expected_value,
"actual_value": actual_value,
}
)
with open("./data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=4)
assert actual_value == expected_value
# Reformatted tests
def test_me_1(send_to_test):
# setup
data = []
x, y = send_to_test(3)
# tests
run_test(
test_func=inspect.stack()[0][3],
variable="x",
expected_value=3 ** 2,
actual_value=x,
data=data,
)
run_test(
test_func=inspect.stack()[0][3],
variable="y",
expected_value=3 ** 3,
actual_value=y,
data=data,
)
run_test(
test_func=inspect.stack()[0][3],
variable="y",
expected_value=3 ** 2,
actual_value=y,
data=data,
)
因此,当您 运行 pytest 时,会创建一个包含预期内容的新 data.json
文件:
[
{
"func": "test_me_1",
"variable": "x",
"expected_value": 9,
"actual_value": 9
},
{
"func": "test_me_1",
"variable": "y",
"expected_value": 27,
"actual_value": 27
},
{
"func": "test_me_1",
"variable": "y",
"expected_value": 9,
"actual_value": 27
}
]
@hoefling 通过在 conftest 中使用以下挂钩的非常简单的解决方案回答了我的问题:
def pytest_assertrepr_compare(op, left, right):...
def pytest_assertion_pass(item, lineno, orig, expl):...
根据 Pytest 文档,我必须添加到 pytest.ini enable_assertion_pass_hook=true 并删除 .pyc 文件,但除此之外它的工作原理非常棒。
现在我已经对使用的运算符进行了左右比较(pytest_assertrepr_compare),如果测试通过了(pytest_assertion_pass)。
我想将有关测试的数据收集到外部数据库,我将在其中收集所有断言并解析预期值与实际结果。
在代码中描述我想要的东西:
test_something.py:
def test_me_1(send_to_test):
"""
Docstring to pad even more
"""
x,y = send_to_test(3)
assert x == 3**2
assert y == 3**3
assert y == 3**2 # I want this to fail intentionally
conftest.py:
@pytest.fixture(scope='function')
def send_to_test() -> Callable:
return lambda x: (x ** 2, x ** 3)
我要收集的数据是(其他任何方式都可以,只要我得到这个数据):
test_data = [{'func': 'test_me_1', 'variable': 'x', 'expected_value': 9, 'actual_value': 9},
{'func': 'test_me_1', 'variable': 'y', 'expected_value': 27, 'actual_value': 27},
{'func': 'test_me_1', 'variable': 'y', 'expected_value': 27, 'actual_value': 9}]
我目前的想法是一个包装器,它可以很容易地实现到现有的测试中,并将收集断言语句及其值。
如果我使用 AST,收集 assert 语句的数量很简单,但这些仅适用于静态分析。
我也尝试过使用 inspect 模块,但很难弄清楚如何为此目的使用它
到目前为止我的失败尝试(打印语句是临时的,因为我想收集数据)
def get_this(func: Callable):
@functools.wraps(func)
def wrapper(*arg, **kwargs):
print(func.__name__)
func_content = inspect.getsource(func)
func_root = ast.parse(func_content)
for node in func_root.body:
for content in node.body:
if isinstance(content, ast.Assert):
print(content)
return func(*arg, **kwargs)
return wrapper
你可以试试这个:
import inspect
import json
from typing import Callable
import pytest
@pytest.fixture(scope="function")
def send_to_test() -> Callable:
return lambda x: (x ** 2, x ** 3)
# Helper function to run and monitor a test
def run_test(test_func, variable, expected_value, actual_value, data):
try:
with open("./data.json", "r") as f:
data = json.load(f)
except FileNotFoundError:
data = []
data.append(
{
"func": test_func,
"variable": variable,
"expected_value": expected_value,
"actual_value": actual_value,
}
)
with open("./data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=4)
assert actual_value == expected_value
# Reformatted tests
def test_me_1(send_to_test):
# setup
data = []
x, y = send_to_test(3)
# tests
run_test(
test_func=inspect.stack()[0][3],
variable="x",
expected_value=3 ** 2,
actual_value=x,
data=data,
)
run_test(
test_func=inspect.stack()[0][3],
variable="y",
expected_value=3 ** 3,
actual_value=y,
data=data,
)
run_test(
test_func=inspect.stack()[0][3],
variable="y",
expected_value=3 ** 2,
actual_value=y,
data=data,
)
因此,当您 运行 pytest 时,会创建一个包含预期内容的新 data.json
文件:
[
{
"func": "test_me_1",
"variable": "x",
"expected_value": 9,
"actual_value": 9
},
{
"func": "test_me_1",
"variable": "y",
"expected_value": 27,
"actual_value": 27
},
{
"func": "test_me_1",
"variable": "y",
"expected_value": 9,
"actual_value": 27
}
]
@hoefling 通过在 conftest 中使用以下挂钩的非常简单的解决方案回答了我的问题:
def pytest_assertrepr_compare(op, left, right):...
def pytest_assertion_pass(item, lineno, orig, expl):...
根据 Pytest 文档,我必须添加到 pytest.ini enable_assertion_pass_hook=true 并删除 .pyc 文件,但除此之外它的工作原理非常棒。 现在我已经对使用的运算符进行了左右比较(pytest_assertrepr_compare),如果测试通过了(pytest_assertion_pass)。