【问题标题】:Pytest execute specific functions but not main()Pytest 执行特定功能但不执行 main()
【发布时间】:2021-09-15 13:59:43
【问题描述】:

我正在完成 udemy 的 Python 编码课程,并且有一个 project,其目录结构如下:

├── LICENSE
├── README.md
├── __init__.py
├── requirements.txt
├── src
│   ├── __init__.py
│   └── milage_converter.py
└── tests
    ├── __init__.py
    └── milage_converter_test.py

milage_converter_test.py 内,我正在运行一些简单的测试,例如:

from py_exercises.src import milage_converter


def test_base_milage_string_to_float(monkeypatch):
    # monkeypatch the "input" function, so that it returns "10".
    monkeypatch.setattr('builtins.input', lambda _: "10")
    assert milage_converter.get_base_milage(1) == 10.0

但这些似乎是在调用milage_converter.py 中的main() 函数。

def get_conversion_direction():
    """Gets the conversion direction input from a user, converts to a float and returns."""
    user_input = input(
        "Would you like to convert from (1) Miles to Kilometers or (2) Kilometers to Miles: ")
    try:
        user_input = float(user_input)
    except ValueError:
        print(
            "Invalid input, options are 1 for Miles to Kilometer or 2 for Kilometers to Miles.")
        get_conversion_direction()
    while user_input in (1, 2):
        user_input = input(
            "You chose an invalid value, please enter a value of 1 or 2: ")
    return user_input


def get_base_milage(unit):
    """Gets the milage input from a user, converts to a float and returns."""
    in_milage = input(f"Please input a value in {unit} to convert: ")
    try:
        in_milage = float(in_milage)
    except ValueError:
        print(
            "Invalid input, please input a valid numerical value to convert.")
        # Adding return avoids the exception being returned:
        # https://stackoverflow.com/a/39059651/2816893
        return get_base_milage(unit)
    return in_milage


def main():
    direction = get_conversion_direction()
    if direction == 1:
        print(
            f"You have selected {direction}, converting from Miles to Kilometers.")
        miles = int(get_base_milage("Miles"))
        print(f"{miles} Miles is equal to {round(miles * 1.609344, 2)}")
    else:
        print(
            f"You have selected {direction}, converting from Kilometers to Miles.")
        kilometers = get_base_milage("Kilometers")
        print(f"{kilometers} Kilometers is equal to {round(kilometers / 1.609344, 2)}")


main()

当我从项目目录运行pytest 时,我收到输入提示,就好像我运行了milage_converter.py 模块,如python3.9 milage_converter.py。这是抛出pytest 无法捕获标准输入的错误。

------------------------------------------------------------------------------------------ Captured stdout -------------------------------------------------------------------------------------------
Would you like to convert from (1) Miles to Kilometers or (2) Kilometers to Miles: 
====================================================================================== short test summary info =======================================================================================
ERROR tests/milage_converter_test.py - OSError: pytest: reading from stdin while output is captured!  Consider using `-s`.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
========================================================================================== 1 error in 0.10s ==========================================================================================

我所期望的是pytest 会简单地调用指定的函数get_base_milage() 并模拟输入。如果我在 milage_converter.py 的第 51 行注释掉 main()pytest 会按我的预期运行,所以我觉得我在这里缺少 python 中的 pytest/mocking 的东西。

【问题讨论】:

    标签: python-3.x pytest pytest-mock


    【解决方案1】:

    如果您打算将 milage_converter.py 作为脚本运行,例如python milage_converter.py,那么检查它是否是 __main__ 是一个好习惯:

    一个模块可以通过检查它自己的名称来发现它是否在主范围内运行,这允许一个常见的习惯用法来在模块中作为脚本运行时有条件地执行代码或使用 python -m 但不是在导入时

    if __name__ == "__main__":
        # execute only if run as a script
        main()
    

    所以把它添加到你的 milage_converter.py

    ...
    if __name__ == '__main__':
        main()
    

    您的测试失败的原因是因为当您通过from py_exercises.src import milage_converter 导入文件时(此时还没有活动补丁),它当然会读取文件中的代码。而且由于您对main() 的调用就在那里,那么它也会立即执行。现在有了这个条件,它将是False,因此不会再执行它了。

    相关参考:

    【讨论】:

    • 非常感谢您提供有效的答案和详细信息。
    猜你喜欢
    • 1970-01-01
    • 2017-10-13
    • 2014-05-03
    • 1970-01-01
    • 2018-02-03
    • 2022-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多