接收和显示用户输入的Doctesting函数-Python(让我毛骨悚然)

接收和显示用户输入的Doctesting函数-Python(让我毛骨悚然),python,user-input,doctest,Python,User Input,Doctest,我目前正在用Python(3.1)编写一个小应用程序,就像一个好孩子一样,我正在一边做文档测试。然而,我遇到了一种我似乎无法验证的方法。它包含一个input(),正因为如此,我不能完全确定应该在doctest的“预期”部分放置什么 下面是说明我的问题的示例代码: """ >>> getFiveNums() Howdy. Please enter five numbers, hit <enter> after each one Please type in a num

我目前正在用Python(3.1)编写一个小应用程序,就像一个好孩子一样,我正在一边做文档测试。然而,我遇到了一种我似乎无法验证的方法。它包含一个
input()
,正因为如此,我不能完全确定应该在doctest的“预期”部分放置什么

下面是说明我的问题的示例代码:

"""
>>> getFiveNums()
Howdy. Please enter five numbers, hit <enter> 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 <enter> 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)
“”“
>>>getFiveNums()
您好。请输入五个数字,每个数字后按
请输入一个号码:
请输入一个号码:
请输入一个号码:
请输入一个号码:
请输入一个号码:
"""
进口医生测试
数字=列表()
#在列表中存储5个用户输入的数字(目前为字符串)
def getFiveNums():
打印(“您好,请输入五个数字,每个数字后按一下”)
对于范围(5)中的i:
newNum=输入(“请键入一个数字:”)
numbers.append(newNum)
打印(“这是您的号码:”,号码)
如果名称=“\uuuuu main\uuuuuuuu”:
doctest.testmod(verbose=True)
运行doctests时,程序在打印“Expecting”部分后立即停止执行,等待我依次输入五个数字(无提示),然后继续。如下图所示:


我不知道我可以在doctest的Expecting部分放置什么来测试一个接收然后显示用户输入的方法。所以我的问题(最后)是,这个函数是可测试的吗?使这个函数可测试的最简单方法是:

因此,在您的doctest中,您实际上测试了
getFiveNums(伪输入)


此外,通过现在打破对
输入的直接依赖,如果您以后要将此代码移植到其他不使用命令行的代码,您可以直接插入新代码来检索输入(无论是GUI应用程序中的对话框,还是基于web的应用程序中的Javascript弹出窗口,等等).

我知道您要求的是doctest答案,但我想建议这种函数可能不是doctest的理想候选函数。我在文档中使用doctest多于在测试中使用doctest,而在IMHO中使用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个用户输入的数字(目前为字符串)
def getFiveNums():
数字=[]
打印“您好,请输入五个数字,每个数字后按”
对于范围(5)中的i:
newNum=输入(“请键入一个数字:”)
numbers.append(newNum)
返回号码
def模拟输入(虚拟提示):
返回1
类TestGetFiveNums(unittest.TestCase):
def设置(自):
self.saved\u input=\uu内置\uuu.input
__内置输入=模拟输入
def拆卸(自):
__内置输入=自保存输入
def testGetFiveNums(自):
打印行=getFiveNums()
self.assertEquals(打印行[1,1,1,1,1])
如果名称=“\uuuuu main\uuuuuuuu”:
unittest.main()

这可能不是对你提出的函数进行精确的测试,但是你得到了这个想法

我找到了另一种方法

"""
>>> get_five_nums(testing=True)
Howdy. Please enter five numbers, hit <enter> after each one.
Please type in a number: 1
Please type in a number: 1
Please type in a number: 1
Please type in a number: 1
Please type in a number: 1
Here is a list of the numbers you entered:  [1, 1, 1, 1, 1]
>>>
"""

import doctest

numbers = []

def get_five_nums(testing=False):
    """Stores 5 user-entered numbers (strings, for now) in a list."""

    print("Howdy. Please enter five numbers, hit <enter> after each one.")
    for i in range(5):
        new_num = int(input("Please type in a number: "))
        if testing:
            print(new_num)
        numbers.append(new_num)
    print("Here is a list of the numbers you entered: ", numbers)


if __name__ == "__main__":
    doctest.testmod(verbose=True)  
五个一。每行一个

要测试您的程序,请在终端或命令提示符下执行以下操作(我使用的是mac):

$python foo.py

这对于任何程序上的任何类型的用户输入都是容易更改的。有了它,您现在可以复制终端会话的输出并将其用作doctest

注意:终端中的函数调用将是get\u five\u nums()。在您的doctest中,它需要获取五个数值(testing=True)


尽管doctest似乎不打算以这种方式使用,但它仍然是一个方便的黑客工具。

我提出了一个解决方案。这有点笨拙,但它在只需要一行输入时工作:

def capitalize_name():
    """
    >>> import io, sys ; sys.stdin = io.StringIO("Bob")  # input
    >>> capitalize_name()
    What is your name?  Your name is BOB!
    """
    name = input('What is your name?  ')
    print('Your name is ' + name.upper() + '!')
不幸的是,当输入包含换行符(例如,“Bob\nAlice”)时,它会发出抱怨。我怀疑这是由于
doctest
解析器被淹没(但我不能肯定)

您可以使用
chr(10)
来绕过“\n”问题,如下所示:

# stores 5 user-entered numbers (strings, for now) in a list
def getFiveNums():
    """
    >>> import io, sys ; sys.stdin = io.StringIO(chr(10).join(['1','2','3','4','5']))  # input
    >>> getFiveNums()
    Howdy. Please enter five numbers, hit <enter> 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:Here are your numbers:  ['1', '2', '3', '4', '5']
    """
    print("Howdy. Please enter five numbers, hit <enter> after each one")
    numbers = []
    for _ in range(5):
        newNum = input("Please type in a number:")
        numbers.append(newNum)
    print("Here are your numbers: ", numbers)
#在列表中存储5个用户输入的数字(暂时为字符串)
def getFiveNums():
"""
>>>导入io,sys;sys.stdin=io.StringIO(chr(10).join(['1','2','3','4','5'))#输入
>>>getFiveNums()
您好。请输入五个数字,每个数字后按
请键入数字:请键入数字:请键入数字:请键入数字:请键入数字:请键入数字:这是您的数字:['1','2','3','4','5']
"""
打印(“您好,请输入五个数字,每个数字后按一下”)
数字=[]
对于范围(5)内的uu:
newNum=输入(“请键入一个数字:”)
numbers.append(newNum)
打印(“这是您的号码:”,号码)
这甚至更麻烦,但它确实有效。您需要记住,所有提示文本(通过input()函数)都显示为输出,而不附带用户输入。(这就是为什么“请键入一个数字:”在一行中出现五次,其实例之间没有空格或换行符。)


虽然这个解决方案确实有效,但请记住,它比其他一些给定的解决方案更难阅读和维护。当你决定使用哪种方法时,这是要考虑的问题。

< P>我可以同意KLUDGY,但是要稍微减少一点,为什么不增加一个小函数来保存大部分的KLUGY(并且在测试时加上一个测试):

我确实同意doctest可能不是这种类型测试的最佳解决方案,但我发现自己使用doctest for TDD,我喜欢在编写测试时不必离开文件甚至函数的简单性,因此我也可能希望以同样的方式完成这样的测试。也就是说,如何编写getFiveNums()的方法
1
1
1
1
1
def capitalize_name():
    """
    >>> import io, sys ; sys.stdin = io.StringIO("Bob")  # input
    >>> capitalize_name()
    What is your name?  Your name is BOB!
    """
    name = input('What is your name?  ')
    print('Your name is ' + name.upper() + '!')
# stores 5 user-entered numbers (strings, for now) in a list
def getFiveNums():
    """
    >>> import io, sys ; sys.stdin = io.StringIO(chr(10).join(['1','2','3','4','5']))  # input
    >>> getFiveNums()
    Howdy. Please enter five numbers, hit <enter> 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:Here are your numbers:  ['1', '2', '3', '4', '5']
    """
    print("Howdy. Please enter five numbers, hit <enter> after each one")
    numbers = []
    for _ in range(5):
        newNum = input("Please type in a number:")
        numbers.append(newNum)
    print("Here are your numbers: ", numbers)
def redirInput(*lines):
    """
    >>> import sys
    >>> redirInput('foo','bar')
    >>> sys.stdin.readline().strip()
    'foo'
    >>> sys.stdin.readline().strip()
    'bar'
    """
    import sys,io
    sys.stdin = io.StringIO(chr(10).join(lines))


def getFiveNums():
    """
    >>> redirInput('1','2','3','4','5')
    >>> getFineFums()
    ... rest as already written ...