I am completing a python coding course from udemy, and have a project with a directory structure like:
├── LICENSE
├── README.md
├── __init__.py
├── requirements.txt
├── src
│ ├── __init__.py
│ └── milage_converter.py
└── tests
├── __init__.py
└── milage_converter_test.py
Within milage_converter_test.py
I am running some simple tests like:
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
But these seem to be invoking the main()
function in milage_converter.py
.
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()
When I run pytest
from the project directory, I get prompted for input as though I had ran the milage_converter.py
module like python3.9 milage_converter.py
. This is throwing an error that pytest
cannot capture stdin.
------------------------------------------------------------------------------------------ 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 ==========================================================================================
What I expected is that pytest
would simply invoke the function specified, get_base_milage()
and mock out the input. If I comment out main()
on line 51 of milage_converter.py pytest
does run as I expect, so I feel like I'm missing something here with pytest/mocking in python.