如何使用Unittest测试来测试Python脚本中的标准输入和标准输出?

胡安·安东尼奥

我正在尝试测试标准输入(使用raw_input()读取并以简单的打印方式编写)的Python脚本(2.7),但是我找不到该怎么做的方法,并且我确定这个问题是很简单。

这是我脚本的非常非常恢复的代码:

def example():
    number = raw_input()
    print number

if __name__ == '__main__':
    example()

我想编写一个单元测试来检查这一点,但是我找不到如何做。我正在尝试使用StringIO和其他方法,但是我找不到真正做到这一点的解决方案。

有人有主意吗?

PD:当然,在真实的脚本中,我使用具有几行和其他类型数据的数据块。

太感谢了。

编辑:

非常感谢您提供的第一个真正具体的答案,它非常完美,仅在导入时遇到了一些问题StringIO,因为我正在执行导入StringIO,并且需要进行类似的导入from StringIO import StringIO(我不太清楚为什么),但是它可能会起作用。

但是我用这种方法发现了另一个问题,在我的项目中,我需要用这种方法测试脚本(在您的支持下,脚本可以很好地工作),但是我想这样做:我有一个传递了很多测试的文件一个脚本,所以我打开文件并读取带有结果块的信息块,并且我想这样做,代码将能够处理检查其结果的块并与其他对象进行同样的操作...

像这样的东西:

class Test(unittest.TestCase):
    ...
    #open file and process saving data like datablocks and results
    ...
    allTest = True
    for test in tests:
        stub_stdin(self, test.dataBlock)
        stub_stdouts(self)
        runScrip()
        if sys.stdout.getvalue() != test.expectResult:
            allTest = False

    self.assertEqual(allTest, True)

我知道也许单元测试现在没有意义,但是您可以对我想要的做个想法。因此,这种方式失败了,我也不知道为什么。

元烤面包机

典型的技术包括模拟标准sys.stdinsys.stdout所需的项目。如果您不关心Python 3的兼容性,则可以使用该StringIO模块,但是,如果您想向前思考并愿意限制于Python 2.7和3.3+,则可以在不太多的情况下以这种方式同时支持Python 2和3在io模块中工作(但需要进行一些修改,但是暂时搁置此想法)。

假设您已经准备好了unittest.TestCase,可以创建一个实用程序函数(或同一类中的方法),该函数将替换sys.stdin/,sys.stdout如下所述。首先进口:

import sys
import io
import unittest

在我最近的一个项目中,我已经为stdin做到了这一点,在stdin中,str用户(或通过管道的另一个程序)将以stdin的形式输入到您的输入中:

def stub_stdin(testcase_inst, inputs):
    stdin = sys.stdin

    def cleanup():
        sys.stdin = stdin

    testcase_inst.addCleanup(cleanup)
    sys.stdin = StringIO(inputs)

至于stdout和stderr:

def stub_stdouts(testcase_inst):
    stderr = sys.stderr
    stdout = sys.stdout

    def cleanup():
        sys.stderr = stderr
        sys.stdout = stdout

    testcase_inst.addCleanup(cleanup)
    sys.stderr = StringIO()
    sys.stdout = StringIO()

请注意,在这两种情况下,它都接受一个测试用例实例,并调用其addCleanup方法,方法添加了cleanup函数调用,函数调用将把它们重置为结束测试方法持续时间时的位置。效果是,从在测试用例中调用它到结束为止的整个过程中,sys.stdout都将用该io.StringIO版本替换朋友,这意味着您可以轻松地检查其值,而不必担心会乱成一团。

最好以这个为例。要使用此功能,您可以简单地创建一个测试用例,如下所示:

class ExampleTestCase(unittest.TestCase): 

    def test_example(self):
        stub_stdin(self, '42')
        stub_stdouts(self)
        example()
        self.assertEqual(sys.stdout.getvalue(), '42\n')

现在,在Python 2中,只有当StringIO类来自StringIO模块时,此测试才能通过,而在Python 3中,则不存在这样的模块。您可以做的是使用io模块中的版本,并对其进行修改,使其在接受的输入方面稍微宽松一些,以便Unicode编码/解码将自动完成,而不是触发异常(例如printPython中的语句)如果没有以下内容,则2不能很好地工作)。我通常这样做是为了在Python 2和3之间实现交叉兼容性。

class StringIO(io.StringIO):
    """
    A "safely" wrapped version
    """

    def __init__(self, value=''):
        value = value.encode('utf8', 'backslashreplace').decode('utf8')
        io.StringIO.__init__(self, value)

    def write(self, msg):
        io.StringIO.write(self, msg.encode(
            'utf8', 'backslashreplace').decode('utf8'))

现在,将示例函数以及此答案中的每个代码片段插入一个文件,您将获得可在Python 2和3中运行的自包含单元测试(尽管您需要print在Python 3中作为函数调用)以针对stdio进行测试。

还有一点要注意:如果每个测试方法都需要,则可以始终将stub_函数调用放在setUp方法中TestCase

当然,如果要使用各种与模拟相关的库来存根stdin / stdout,则可以随意这样做,但是如果这是您的目标,则这种方式不依赖任何外部依赖项。


对于第二个问题,必须以某种方式编写测试用例,这些测试用例必须封装在一个方法中,而不是在类级别,否则原始示例将失败。但是,您可能想要执行以下操作:

class Test(unittest.TestCase):

    def helper(self, data, answer, runner):
        stub_stdin(self, data)
        stub_stdouts(self)
        runner()
        self.assertEqual(sys.stdout.getvalue(), answer)
        self.doCleanups()  # optional, see comments below

    def test_various_inputs(self):
        data_and_answers = [
            ('hello', 'HELLOhello'),
            ('goodbye', 'GOODBYEgoodbye'),
        ]

        runScript = upperlower  # the function I want to test 

        for data, answer in data_and_answers:
            self.helper(data, answer, runScript)

您可能要调用的原因doCleanups是为了防止清理堆栈变得像所有data_and_answers一样深,但这会从清理堆栈中弹出所有内容,因此如果最后还有其他需要清理的内容这可能最终会带来问题-您可以随意离开那里,因为所有与stdio相关的对象都将以相同顺序还原到最后,因此真正的对象将始终在那里。现在我要测试的功能:

def upperlower():
    raw = raw_input()
    print (raw.upper() + raw),

因此,是的,我所做的一些解释可能会有所帮助:请记住,在一个TestCase类中,该框架严格依赖实例assertEqual和其朋友来使其起作用。因此,为了确保在正确的级别上进行测试,您真的想一直调用这些断言,以便在发生错误时输入/答案显示不正确的错误消息会显示出有用的错误消息,而不是正确地显示这些错误消息。直到最后,就像您对for循环所做的一样(这将告诉您出了点问题,但不完全是数百个错误中的哪一个,现在您很生气)。也是helper方法-您可以将其命名为任意名称,只要它不以test因为该框架将尝试将其作为一个整体运行,并且将严重失败。因此,只要遵循此约定,您就可以在测试用例中基本包含模板以运行测试-然后可以像我一样在带有大量输入/输出的循环中使用它。

至于您的其他问题:

只是我在导入StringIO时遇到了一些问题,因为我正在执行导入StringIO,并且需要从StringIO导入,就像从StringIO导入StringIO(我真的不明白为什么),但事实上,它确实可行。

好吧,如果您看一下我的原始代码,我确实向您展示了如何做import io,然后io.StringIO通过定义覆盖了该类class StringIO(io.StringIO)但是它对您有用,因为您严格地从Python 2来执行此操作,而考虑到不到5年将不支持Python 2,我会尽一切可能将针对Python 3的答案作为目标。想想将来可能正在阅读此帖子的与您有类似问题的用户。无论如何,是的,原始的from StringIO import StringIO作品,因为那StringIOStringIO模块中虽然from cStringIO import StringIO应该可以导入模块C版本StringIO之所以起作用,是因为它们都提供了足够接近的接口,因此它们基本上可以按预期工作(直到您尝试在Python 3下运行它)。

再次,将所有这些与我的代码放在一起应该会产生一个自包含的工作测试脚本请记住要阅读文档并遵循代码的形式,而不要发明自己的语法并希望事情能够起作用(以及确切地说,为什么您的代码不起作用,因为“测试”代码是在类所在的位置定义的)正在构建中,因此所有这些操作都是在Python导入模块时执行的,并且由于测试运行所需的所有东西甚至都不可用(即,类本身甚至还不存在),因此整个过程只是因抽搐而死)。我想,即使您面临的问题确实很普遍,但在这里问问题也有帮助,没有一个快速简单的名称来搜索您的确切问题确实使您很难弄清楚哪里出了问题。:)无论如何,祝您好运,并且对您努力测试代码也有好处。


还有其他方法,但是鉴于我在SO上查看的其他问题/答案似乎无济于事,所以我希望这一方法能解决这一问题。其他参考:

当然,它剥开重复这一切可以用做unittest.mockPython中可供3.3+或PyPI上的原/滚动反向移植版本,但考虑到这些库隐藏了一些什么实际发生的错综复杂的,他们可能会隐藏一些的有关实际发生(或需要发生)或重定向实际发生方式的详细信息。如果需要,您可以继续阅读unittest.mock.patch并略微进入StringIO补丁sys.stdout部分。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在 bash 脚本中重定向标准输入和标准输出

来自分类Dev

在Python中,测试函数的标准输出

来自分类Dev

在Python中,测试函数的标准输出

来自分类Dev

如何测试写入标准输出的代码?

来自分类Dev

在R data.table中,如何使用训练集的均值和标准差标准化测试集

来自分类Dev

如何在Java中重置标准输入和输出?

来自分类Dev

用鱼测试标准输出

来自分类Dev

Python文件处理:标准输入和输出

来自分类Dev

重定向标准输入和标准输出

来自分类Dev

重定向标准输入和标准输出?

来自分类Dev

阅读并打印“标准输入和标准输出”

来自分类Dev

如何从标准输出和标准错误中删除^ M

来自分类Dev

C复制功能测试。如何使用数据驱动的TSV在机器人框架中传递标准输入以进行处理?

来自分类Dev

C复制功能测试。如何使用数据驱动的TSV在机器人框架中传递标准输入以进行处理?

来自分类Dev

使用\ Sexpr标准化输出测试统计信息

来自分类Dev

使用\ Sexpr标准化输出测试统计信息

来自分类Dev

无法使用单元测试捕获标准输出

来自分类Dev

使用AutoBench对大型输入进行测试时,无效标准报告

来自分类Dev

如何从getopts在bash脚本中输出管道标准输出?

来自分类Dev

如何在Shell脚本中获取Java应用程序的退出状态,标准输出和标准错误流?

来自分类Dev

如何使用Highline测试Cucumber用户的输入和输出?

来自分类Dev

Pytest捕获特定测试的标准输出

来自分类Dev

在bash中,使用标准输入执行脚本时,如何自动输入值?

来自分类Dev

如何在仍在运行的标准输入中写入进程标准输入并从其标准输出中读取?

来自分类Dev

使用exiv2或imagemagick从标准输入中删除EXIF数据并输出到标准输出

来自分类Dev

关闭标准输出或标准输入

来自分类Dev

如何使用 Python Unittest 定义测试方法

来自分类Dev

脚本写入标准输出和标准错误时如何防止Cron电子邮件

来自分类Dev

如何查看在automator中运行的脚本的标准输出

Related 相关文章

  1. 1

    在 bash 脚本中重定向标准输入和标准输出

  2. 2

    在Python中,测试函数的标准输出

  3. 3

    在Python中,测试函数的标准输出

  4. 4

    如何测试写入标准输出的代码?

  5. 5

    在R data.table中,如何使用训练集的均值和标准差标准化测试集

  6. 6

    如何在Java中重置标准输入和输出?

  7. 7

    用鱼测试标准输出

  8. 8

    Python文件处理:标准输入和输出

  9. 9

    重定向标准输入和标准输出

  10. 10

    重定向标准输入和标准输出?

  11. 11

    阅读并打印“标准输入和标准输出”

  12. 12

    如何从标准输出和标准错误中删除^ M

  13. 13

    C复制功能测试。如何使用数据驱动的TSV在机器人框架中传递标准输入以进行处理?

  14. 14

    C复制功能测试。如何使用数据驱动的TSV在机器人框架中传递标准输入以进行处理?

  15. 15

    使用\ Sexpr标准化输出测试统计信息

  16. 16

    使用\ Sexpr标准化输出测试统计信息

  17. 17

    无法使用单元测试捕获标准输出

  18. 18

    使用AutoBench对大型输入进行测试时,无效标准报告

  19. 19

    如何从getopts在bash脚本中输出管道标准输出?

  20. 20

    如何在Shell脚本中获取Java应用程序的退出状态,标准输出和标准错误流?

  21. 21

    如何使用Highline测试Cucumber用户的输入和输出?

  22. 22

    Pytest捕获特定测试的标准输出

  23. 23

    在bash中,使用标准输入执行脚本时,如何自动输入值?

  24. 24

    如何在仍在运行的标准输入中写入进程标准输入并从其标准输出中读取?

  25. 25

    使用exiv2或imagemagick从标准输入中删除EXIF数据并输出到标准输出

  26. 26

    关闭标准输出或标准输入

  27. 27

    如何使用 Python Unittest 定义测试方法

  28. 28

    脚本写入标准输出和标准错误时如何防止Cron电子邮件

  29. 29

    如何查看在automator中运行的脚本的标准输出

热门标签

归档