Pythonic相当于./foo.py< bar.png

时间:2010-10-16 09:05:12

标签: python unit-testing

我有一个从sys.stdin读取的Python程序,所以我可以用./foo.py < bar.png来调用它。如何在另一个Python模块中测试此代码?也就是说,如何在运行测试脚本时将stdin设置为指向文件的内容?我不想做像./test.py < test.png这样的事情。我不认为我可以使用fileinput,因为输入是二进制的,我只想处理一个文件。该文件是使用PIL中的Image.open(sys.stdin)打开的。

4 个答案:

答案 0 :(得分:3)

除了用作独立程序之外,您应该对脚本进行概括,以便可以从测试脚本调用它。这是一个执行此操作的示例脚本:

#! /usr/bin/python

import sys

def read_input_from(file):
    print file.read(),

if __name__ == "__main__":
    if len(sys.argv) > 1:
        # filename supplied, so read input from that
        filename = sys.argv[1]
        file = open(filename)
    else:
        # no filename supplied, so read from stdin
        file = sys.stdin
    read_input_from(file)

如果使用文件名调用,则会显示该文件的内容。否则,将显示从stdin读取的输入。 (能够在命令行上传递文件名可能是对foo.py脚本的有用改进。)

在测试脚本中,您现在可以使用文件调用foo.py中的函数,例如:

#! /usr/bin/python

import foo

file = open("testfile", "rb")
foo.read_input_from(file)

答案 1 :(得分:2)

  • 您的函数或类应接受流而不是选择要使用的流。
  • 您的main函数会选择sys.stdin
  • 您的测试方法可能会选择StringIO实例或测试文件。

该计划:

# foo.py
import sys
from PIL import Image

def foo(stream):
  im = Image.open(stream)
  # ...

def main():
  foo(sys.stdin)

if __name__ == "__main__":
  main()

测试:

# test.py
import StringIO, unittest
import foo

class FooTest(unittest.TestCase):
  def test_foo(self):

    input_data = "...."
    input_stream = StringIO.StringIO(input_data)
    # can use a test file instead:
    # input_stream = open("test_file", "rb")

    result = foo.foo(input_stream)
    # asserts on result

if __name__ == "__main__":
  unittest.main()

答案 2 :(得分:1)

comp.lang.python post显示方式:替换sys.stdout的StringIO()对象,然后使用getvalue()获取输出:

def setUp(self):
    """Set stdin and stdout."""
    self.stdin_backup = sys.stdin

    self.stdout_backup = sys.stdout
    self.output_stream = StringIO()
    sys.stdout = self.output_stream

    self.output_file = None


def test_standard_file(self):
    sys.stdin = open(EXAMPLE_PATH)
    foo.main()
    self.assertNotEqual(
        self.output_stream.getvalue(),
        '')


def tearDown(self):
    """Restore stdin and stdout."""
    sys.stdin = self.stdin_backup
    sys.stdout = self.stdout_backup

答案 3 :(得分:0)

你可以随时修补你的stdin。但这是非常丑陋的方式。如理查德建议的那样,更好地概括你的脚本。

import sys
import StringIO

mockin = StringIO.StringIO()
mockin.write("foo")
mockin.flush()
mockin.seek(0)

setattr(sys, 'stdin', mockin)

def read_stdin():
    f = sys.stdin
    result = f.read()
    f.close()
    return result

print read_stdin()

此外,请勿忘记在拆除考试时恢复stdin