Pytest:摆脱装饰器引入的测试函数中使用的冗余代码
Pytest: Get rid of redudant Code used in testfunctions introduced by decorators
我得到了以下非常简单的函数和测试:
from feedback import error_msg, info_msg, warn_msg
import pytest
def test_message_info(capsys):
@info_msg
def message():
return "testmessage"
message()
assert capsys.readouterr().out == "INFO: testmessage\n"
def test_message_error(capsys):
@error_msg
def message():
return "testmessage"
message()
assert capsys.readouterr().out == "ERROR: testmessage\n"
def test_message_warning(capsys):
@warn_msg
def message():
return "testmessage"
message()
assert capsys.readouterr().out == "WARN: testmessage\n"
我知道可能有一些方法可以将这些测试减少为使用夹具或 pytest.mark.parametrize
的单个测试,但我不知道如何解决这个问题。有谁知道如何用装饰器做到这一点?
“手动”将装饰器应用于函数,而不是使用装饰器语法糖。然后你可以在一个循环中完成所有三个测试。
from feedback import error_msg, info_msg, warn_msg
import pytest
MESSAGE_BY_DECORATOR = [
(info_msg, "INFO"),
(error_msg, "ERROR"),
(warn_msg, "WARN")]
def test_message_all(capsys):
def message():
return "testmessage"
for decorator, expected in MESSAGE_BY_DECORATOR:
decorated_message = decorator(message)
decorated_message()
assert capsys.readouterr().out == f"{expected}: testmessage\n"
# you'll need to reset your capsys object here
我会使用 @pytest.mark.parametrize
:
import pytest
import functools
# Quickly reimplement the `feedback` decorators, so that this
# example will be runnable. These lines aren't important if
# you're just interested in the answer to the question at hand.
def log_msg(message):
def decorate(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
out = f(*args, **kwargs)
print(f'{message}: {out}')
return wrapper
return decorate
info_msg = log_msg('INFO')
error_msg = log_msg('ERROR')
warn_msg = log_msg('WARN')
# Make a parametrized test:
@pytest.mark.parametrize(
'decorator, expected', [
(info_msg, 'INFO: testmessage\n'),
(error_msg, 'ERROR: testmessage\n'),
(warn_msg, 'WARN: testmessage\n'),
],
)
def test_decorators(decorator, expected, capsys):
@decorator
def message():
return "testmessage"
message()
assert capsys.readouterr().out == expected
(已编辑以使其可运行,并修复了一些错误。)
我得到了以下非常简单的函数和测试:
from feedback import error_msg, info_msg, warn_msg
import pytest
def test_message_info(capsys):
@info_msg
def message():
return "testmessage"
message()
assert capsys.readouterr().out == "INFO: testmessage\n"
def test_message_error(capsys):
@error_msg
def message():
return "testmessage"
message()
assert capsys.readouterr().out == "ERROR: testmessage\n"
def test_message_warning(capsys):
@warn_msg
def message():
return "testmessage"
message()
assert capsys.readouterr().out == "WARN: testmessage\n"
我知道可能有一些方法可以将这些测试减少为使用夹具或 pytest.mark.parametrize
的单个测试,但我不知道如何解决这个问题。有谁知道如何用装饰器做到这一点?
“手动”将装饰器应用于函数,而不是使用装饰器语法糖。然后你可以在一个循环中完成所有三个测试。
from feedback import error_msg, info_msg, warn_msg
import pytest
MESSAGE_BY_DECORATOR = [
(info_msg, "INFO"),
(error_msg, "ERROR"),
(warn_msg, "WARN")]
def test_message_all(capsys):
def message():
return "testmessage"
for decorator, expected in MESSAGE_BY_DECORATOR:
decorated_message = decorator(message)
decorated_message()
assert capsys.readouterr().out == f"{expected}: testmessage\n"
# you'll need to reset your capsys object here
我会使用 @pytest.mark.parametrize
:
import pytest
import functools
# Quickly reimplement the `feedback` decorators, so that this
# example will be runnable. These lines aren't important if
# you're just interested in the answer to the question at hand.
def log_msg(message):
def decorate(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
out = f(*args, **kwargs)
print(f'{message}: {out}')
return wrapper
return decorate
info_msg = log_msg('INFO')
error_msg = log_msg('ERROR')
warn_msg = log_msg('WARN')
# Make a parametrized test:
@pytest.mark.parametrize(
'decorator, expected', [
(info_msg, 'INFO: testmessage\n'),
(error_msg, 'ERROR: testmessage\n'),
(warn_msg, 'WARN: testmessage\n'),
],
)
def test_decorators(decorator, expected, capsys):
@decorator
def message():
return "testmessage"
message()
assert capsys.readouterr().out == expected
(已编辑以使其可运行,并修复了一些错误。)