Python 当测试以文本文件作为输入的功能时,如何传递字符串来代替测试用例?

Python 当测试以文本文件作为输入的功能时,如何传递字符串来代替测试用例?,python,input,text,file-io,pytest,Python,Input,Text,File Io,Pytest,我想充分测试一个类的一些功能: 将强制文本(.txt)文件作为输入 执行一些任意操作 能够提供结果 以下是此设置的示例: # my_class.py class MyClass: def __init__(self, file): self.__some_attr = dict(MyClass.__process_text_file(file) # ... @staticmethod def __process_text_file(

我想充分测试一个类的一些功能:

  • 将强制文本(
    .txt
    )文件作为输入
  • 执行一些任意操作
  • 能够提供结果
以下是此设置的示例:

# my_class.py

class MyClass:
    def __init__(self, file):
        self.__some_attr = dict(MyClass.__process_text_file(file)
        # ...

    @staticmethod
    def __process_text_file(file):
        # file actually used here
        for line in open(file):
            # ...
            yield ("something unique derived from 'line'", "something derived from 'line'")

    def get_thing(self):
        # ...
        return self.__some_attr
使用
pytest
提供测试输入时,我能够成功地通过本地文件,并按预期通过测试:

# test_my_class.py

class TestMyClass:
    def test_input(self):
        expected = (
           "expected\n"
           "results"
        )
        input_file = "path/to/input_file.txt"
        under_test = MyClass(input_file)
        assert under_test.get_thing() == expected
        # success
    def __process_text_file(file):
>       for line in open(file):
E       OSError: [Errno 22] Invalid argument: 'this\nthat'
    def __process_text_file(file):
>       for line in open(file):
E       TypeError: expected str, bytes or os.PathLike object, not _io.StringIO
为了完整起见,这可能是一个示例输入文件:

# input_file.txt
something that leads to the expected
processed results
我希望能够在测试方法中使用字符串,以便于测试多个(可能是参数化的)案例,并避免在我可能希望包含的任何案例中使用
.txt
fixture文件

传入
字符串时

input_file = (
    "this\n"
    "that"
)
我得到了以下结果(如预期的那样):

当传入一个
StringIO
时:

input_file = StringIO(
    "this\n"
    "that"
)
我得到了以下结果(如预期的那样):


考虑到输入是文本文件的要求,如何在测试方法中最好地转换和使用字符串作为输入?

这应该使用StringIO

import io
input_file = io.StringIO(u"your text goes here") # takes unicode as argument
不要在多个带引号的单独字符串中打断该字符串,请尝试以下操作-

"this\nthat"

由于接口需要文件名,因此不能只传递类似文件的对象(如
StringIO
)。最简单的方法可能是使用
mock_open
返回具体的文件内容:

class TestMyClass:
def测试_输入(自身):
...
read_data=“line1\nline2\nline3”
使用补丁(“builtins.open”,mock_open(read_data=read_data)):
result=MyClass(“某些文件名”).get\u thing()
...
另一种可能性是使用模拟完整的文件系统(在您的例子中可能是过度使用)。这看起来像:

class TestMyClass:
def测试_输入(自身,fs):
...
contents=“line1\nline2\nline3”
file\u path=“path/to/input\u file.txt”
创建文件(文件路径,内容=内容)
result=MyClass(文件路径).get\u thing()
...
其中,
fs
是文件系统装置

免责声明:我是pyfakefs的撰稿人


请注意,这两种解决方案都不会在真正的文件系统中创建任何文件—它们都只在内存中工作。

如果要测试某个方法是否打开了文件,则至少需要有一个提供文件的测试,以查看该方法是否打开了文件并基于内容返回某些内容。您仍然可以将文件的打开与迭代和处理分开。您可能需要一个助手类,在执行测试时可以替换不同的部分。你的
dunder
静态方法闻起来像是一个想要诞生的助手类。我不想避免一个测试,它需要一个实际的文件(从而测试文件接受功能),更希望有一个(第二个,很高兴的)测试,它将使测试输入/输出内容变得更容易。我曾考虑过一个helper方法,但我希望这是最后的手段,因为这意味着添加功能以支持测试,这感觉是向后的(并且不是类的要求)。您已经有了一个help方法。最好有一个助手类。无论如何,你不必保留任何有助于通过考试的东西。测试通过后,您可以将设计重构为其他内容。我不清楚
\uu process\u text\u file()
方法。
#…
表示特定于生成结果的实际功能。不要担心。这对我来说似乎很清楚。不幸的是,添加
u
(并且为了完成而进行限定的导入)似乎并没有改变我第二次尝试的解决方案中给出的异常。删除
\n
字符后,结果仍然存在。您是对的,问题是无法将StringIO实例传递到open()-可以尝试使用此方法来伪造文件。链接问题中的解决方案为我提供了足够的帮助来构建测试助手,谢谢。