Функции Doctesting, которые получают и отображают ввод данных пользователем - Python (отрывающий мои волосы)

Я в настоящее время пишу небольшое приложение с 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", ожидает меня для введения пяти номеров один за другим (без подсказок) и затем продолжается. Как показано ниже:

doctest results

Я не знаю то, что, во всяком случае, я могу поместить в раздел Expecting своего doctest, чтобы смочь протестировать метод, который получает и затем отображает ввод данных пользователем. Таким образом, мой вопрос (наконец), действительно ли эта функция doctestable?

6
задан Glorfindel 25 July 2019 в 03:06
поделиться

2 ответа

Я знаю, что вы хотите получить ответ по 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()

Возможно, это не совсем точное тестирование функции, которую вы представили, но вы поняли идею.

5
ответ дан 8 December 2019 в 18:33
поделиться

Самый простой способ сделать это тестируемым - это ввод параметров :

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 в веб-приложении и т. д.).

5
ответ дан 8 December 2019 в 18:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: