Я в настоящее время пишу небольшое приложение с Python (3.1), и как хороший маленький мальчик, я - doctesting, когда я иду. Однако я столкнулся с методом, которым я не могу казаться doctest. Это содержит input()
, из-за этого, я не совсем уверен, что поместить в части "ожидания" doctest.
Пример кода для иллюстрирования моей проблемы следует:
"""
>>> getFiveNums()
Howdy. Please enter five numbers, hit after each one
Please type in a number:
Please type in a number:
Please type in a number:
Please type in a number:
Please type in a number:
"""
import doctest
numbers = list()
# stores 5 user-entered numbers (strings, for now) in a list
def getFiveNums():
print("Howdy. Please enter five numbers, hit after each one")
for i in range(5):
newNum = input("Please type in a number:")
numbers.append(newNum)
print("Here are your numbers: ", numbers)
if __name__ == "__main__":
doctest.testmod(verbose=True)
При выполнении doctests программа прекращает выполняться сразу после печати раздела "Expecting", ожидает меня для введения пяти номеров один за другим (без подсказок) и затем продолжается. Как показано ниже:
Я не знаю то, что, во всяком случае, я могу поместить в раздел Expecting своего doctest, чтобы смочь протестировать метод, который получает и затем отображает ввод данных пользователем. Таким образом, мой вопрос (наконец), действительно ли эта функция doctestable?
Я знаю, что вы хотите получить ответ по doctest, но могу ли я предположить, что этот тип функции не является хорошим кандидатом для doctest. Я использую доктесты для документации больше, чем для тестирования, и доктест для этой функции не будет хорошей документацией ИМХО.
Подход с использованием unitest может выглядеть так:
import unittest
# stores 5 user-entered numbers (strings, for now) in a list
def getFiveNums():
numbers = []
print "Howdy. Please enter five numbers, hit <enter> after each one"
for i in range(5):
newNum = input("Please type in a number:")
numbers.append(newNum)
return numbers
def mock_input(dummy_prompt):
return 1
class TestGetFiveNums(unittest.TestCase):
def setUp(self):
self.saved_input = __builtins__.input
__builtins__.input = mock_input
def tearDown(self):
__builtins__.input = self.saved_input
def testGetFiveNums(self):
printed_lines = getFiveNums()
self.assertEquals(printed_lines, [1, 1, 1, 1, 1])
if __name__ == "__main__":
unittest.main()
Возможно, это не совсем точное тестирование функции, которую вы представили, но вы поняли идею.
Самый простой способ сделать это тестируемым - это ввод параметров :
def getFiveNums(input_func=input):
print("Howdy. Please enter five numbers, hit <enter> after each one")
for i in range(5):
newNum = input_func("Please type in a number:")
numbers.append(newNum)
print("Here are your numbers: ", numbers)
Вы не можете ожидать ввода модульного теста / output - вас не может беспокоить, что вызов input
может каким-то образом не сработать. Ваш лучший вариант - передать какой-нибудь метод заглушки; что-то вроде
def fake_input(str):
print(str)
return 3
Таким образом, в вашем тесте вы фактически тестируете getFiveNums (fake_input)
.
Более того, нарушив прямую зависимость от input
now , если вы позже перенесете этот код на что-то еще, что не использовало командную строку, вы можно просто добавить новый код для получения ввода (будь то диалоговое окно в приложении с графическим интерфейсом пользователя или всплывающее окно Javascript в веб-приложении и т. д.).