And*_*iuc 6 python testing pytest
假设我有一个文件 test_scratch_2.py
import pytest
def my_fun(number: int):
if number == 1:
raise ValueError("Some Message for number 1")
if number == 2:
raise ValueError("Some Message for number 2")
if number == 3:
return int("number")
return number ** 2
@pytest.mark.parametrize("digit", [
# example 1
pytest.param(1, id="first",
marks=pytest.mark.xfail(raises=ValueError,
strict=True,
reason="Some Message for number 1")),
# example 2
pytest.param(2, id="second",
marks=pytest.mark.xfail(raises=ValueError,
strict=True,
reason="Some Message for number 1")),
pytest.param(3, id="third",
marks=pytest.mark.xfail(raises=ValueError,
strict=True,
reason="Some Message for number xxxxxxxxx")),
4,
5,
60000
])
def test_my_fun(digit):
assert my_fun(digit) > 0
Run Code Online (Sandbox Code Playgroud)
我运行测试
import pytest
def my_fun(number: int):
if number == 1:
raise ValueError("Some Message for number 1")
if number == 2:
raise ValueError("Some Message for number 2")
if number == 3:
return int("number")
return number ** 2
@pytest.mark.parametrize("digit", [
# example 1
pytest.param(1, id="first",
marks=pytest.mark.xfail(raises=ValueError,
strict=True,
reason="Some Message for number 1")),
# example 2
pytest.param(2, id="second",
marks=pytest.mark.xfail(raises=ValueError,
strict=True,
reason="Some Message for number 1")),
pytest.param(3, id="third",
marks=pytest.mark.xfail(raises=ValueError,
strict=True,
reason="Some Message for number xxxxxxxxx")),
4,
5,
60000
])
def test_my_fun(digit):
assert my_fun(digit) > 0
Run Code Online (Sandbox Code Playgroud)
在 的情况下存在错误test_scratch_2.py::test_my_fun[third] XFAIL。
它会因预期的异常而失败,但不会因预期的原因而失败。
所有断言都基于异常类型而不是异常消息。
我如何查看异常消息?
You can use pytest's with pytest.raises(ErrorWhichMustBeRaised, match='Error message which must appear'): context manager to achieve the desired behaviour, as suggested in this SO answer to a similar question.
To make this work, I divided your tests into "happy path" tests and "exceptions" tests. Please note that your use of xfail is technically an anti-pattern: "It is better to use the pytest.mark.xfail marker when possible to declare a test to be xfailed under certain conditions like known bugs or missing features." (source: official doc)
Testing the code below (in quiet mode) returns the error message you would want in your case:
============================================================== short test summary info ===============================================================
FAILED main.py::test_my_fun_exceptions[second] - AssertionError: Regex pattern did not match.
FAILED main.py::test_my_fun_exceptions[third] - AssertionError: Regex pattern did not match.
2 failed, 4 passed in 0.11s
Run Code Online (Sandbox Code Playgroud)
Please note that id='third' fails as well. That's because attempting to convert a string to an integer will raise a ValueError with a different error message than the one which appears in the code.
Code (python 3.11.4):
import pytest
def my_fun(number: int):
if number == 1:
raise ValueError("Some Message for number 1")
if number == 2:
raise ValueError("Some Message for number 2")
if number == 3:
return int("number")
return number**2
@pytest.mark.parametrize("digit", [4, 5, 60000])
def test_my_fun(digit):
assert my_fun(digit) > 0
@pytest.mark.parametrize(
"digit, error, match_str",
[
# example 1
(pytest.param(1, ValueError, "Some Message for number 1", id="first")),
# example 2
(pytest.param(2, ValueError, "Some Message for number 1", id="second")
),
# example 3
(pytest.param(
3, ValueError, "Some Message for number xxxxxxxxx", id="third"))
])
def test_my_fun_exceptions(digit, error, match_str):
with pytest.raises(error, match=match_str):
assert my_fun(digit) > 0
Run Code Online (Sandbox Code Playgroud)