调用使用 try/except 捕获异常的函数时,无法在 pytest 中测试 ValueError

Failed to test ValueError in pytest when calling a function that using try/except to catch exception

提问人:Kevinkun 提问时间:5/22/2023 更新时间:5/22/2023 访问量:117

问:

我有这个代码,基本上只是为了在几分钟内找出人们的年龄:

import datetime, inflect, operator, sys


Inflect = inflect.engine()


def main():
    # Ask user for their dob, Wait for return of final year minutes in words
    print(get_year(input("Date of Birth: ")))


def get_year(date):
    # Get and Validate user DOB input
    try:
        # Split each YY MM DD based on -
        date = date.split("-")

        # Convert user input to datetime format
        date = datetime.date(int(date[0]), int(date[1]), int(date[2]))

        # Get years distance between user's input date and today's date
        years_distance = operator.sub(datetime.date.today(), date)

        # Get user age in minutes: Convert years distance to minutes by divide seconds to 60
        # Also Convert to int so we don't get float as result, which we don't want word 'point zero'
        years_distance_in_minutes = int(years_distance.total_seconds() / 60)

        # Conver string numbers to words
        return convert_to_words(years_distance_in_minutes)
    except ValueError:
        sys.exit("Invalid date")


def convert_to_words(minutes):
    # Convert number to words with inflect engine
    words = Inflect.number_to_words(minutes, andword="")
    return words.capitalize() + " minutes"


if __name__ == "__main__":
    main()

这是我的pytest代码:

import pytest
from seasons import get_year


def test_valid_get_year():
    assert get_year("2022-05-22") == "Five hundred twenty-five thousand, six hundred minutes"
    assert get_year("2021-05-22") == "One million, fifty-one thousand, two hundred minutes"
    assert get_year("1997-11-06") == "Thirteen million, four hundred thirty-two thousand, three hundred twenty minutes"


@pytest.mark.parametrize("date", ["cat", "22/05/202", "November 6, 1997", "1999-13-30", "3000-11-06"])
def test_invalid_get_year(date):
    with pytest.raises(ValueError):
        get_year(date)

如果您查看我的函数,它将完美地处理任何无效格式日期,并且会立即使用。get_year()try/exceptsys.exit("Invalid date")

但是当我运行pytest时,这段代码总是失败的:

@pytest.mark.parametrize("date", ["cat", "22/05/202", "November 6, 1997", "1999-13-30", "3000-11-06"])
def test_invalid_get_year(date):
    with pytest.raises(ValueError):
        get_year(date)

输出始终为:

       except ValueError:
>           sys.exit("Invalid date")
E           SystemExit: Invalid date


>       with pytest.raises(ValueError):
E       Failed: DID NOT RAISE <class 'ValueError'>

在我的理解中,pytest 似乎在我的函数中不能完美地工作。有一个示例,我不需要使用,我可以单独验证每行代码并引发 ValueError。try/exceptget_year()try/exceptif/else

但是有没有办法像我一样使用并且必须通过它?try/exceptget_year()pytest

python pytest

评论

2赞 MrBean Bremen 5/22/2023
你的代码捕获了,它不会引发它 - 所以测试输出是正确的。您必须测试 (例如 for )。ValueErrorsys.exitSystemExit
0赞 Kevinkun 5/22/2023
@MrBeanBremen它不起作用。出现了很多错误。

答:

0赞 Yum Lee 5/22/2023 #1

在错误处理期间调用是一种不好的做法。 这行代码本质上是一个断言,告诉pytest期待你的函数出现异常。sys.exitwith pytest.raisesget_year

因为它调用 ,程序在异常之前退出, , 可以到达 pytest,所以它抱怨以下消息:sys.exitValueError

E       Failed: DID NOT RAISE <class 'ValueError'>

删除并让 python 运行时为您处理异常。sys.exit

try:
   ...
except ValueError as err:
    log_your_error(err)
    raise # this will re-raise the error so that pytest sees it

评论

0赞 Kevinkun 5/22/2023
您的代码可以完美地工作。但事情是这样的:目标是在用户输入无效格式日期时退出。在捕获异常后如何处理这个问题?sys.exit()try/except
0赞 Yum Lee 5/22/2023
@Kevinkun尝试在 main 函数中捕获 ValueError 并打印出错误消息并退出。即使您什么都不做,Python 运行时也会打印出默认错误消息并退出。
0赞 Kevinkun 5/22/2023
我刚刚解决了这个问题。在 I do 和 my pytest 中,我更改为 .你怎么看?except ValueError:raise sys.exit("Invalid date")ValueErrorSystemExitwith pytest.raises(SystemExit):
0赞 Yum Lee 5/22/2023
@Kevinkun 是的。这也行得通。该词在该处不是必需的,因为在内部引发 SystemExit 异常。raisesys.exit