Pythonic等效于./foo.py<;bar.png

Pythonic等效于./foo.py<;bar.png,python,unit-testing,Python,Unit Testing,我有一个Python程序,它读取sys.stdin,所以我可以用/foo.py

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

除了作为独立程序使用外,还应概括脚本,以便从测试脚本调用它。下面是一个执行此操作的示例脚本:

#! /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)

除了作为独立程序使用外,还应该对脚本进行泛化,以便可以从测试脚本中调用它。下面是一个执行此操作的示例脚本:

#! /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)

您可以随时对
stdin
进行猴子补丁。但这是相当丑陋的方式。所以最好是按照Richard的建议概括你的脚本

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

您可以随时对
stdin
进行猴补丁。但这是相当丑陋的方式。所以最好是按照Richard的建议概括你的脚本

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。

一个演示方法:用一个StringIO()对象替换sys.stdout,然后使用
getvalue()
获取输出:

A说明了方法:用一个StringIO()对象替换sys.stdout,然后用
getvalue()
获取输出:

  • 您的函数或类应该接受流,而不是选择要使用的流
  • 您的
    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()
  • 您的函数或类应该接受流,而不是选择要使用的流
  • 您的
    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()