0

I'd like to sufficiently test some functionality for a class that:

  • takes a mandatory text (.txt) file as input
  • performs some arbitrary operation
  • is able to provide the result

Below is an example of this setup:

# 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

When providing an test input using pytest, I am able to successfully pass in a local file, and have the test pass as expected:

# 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

For the sake of completion, this might be an example input file:

# input_file.txt
something that leads to the expected
processed results

I would like to be able to use a string within the test method, both for ease of testing multiple (possibly parametrized) cases, and to avoid having a .txt fixture file for any case I may wish to include.

When passing in a string:

input_file = (
    "this\n"
    "that"
)

I get the following (as expected):

    def __process_text_file(file):
>       for line in open(file):
E       OSError: [Errno 22] Invalid argument: 'this\nthat'

When passing in a StringIO:

input_file = StringIO(
    "this\n"
    "that"
)

I get the following (as expected):

    def __process_text_file(file):
>       for line in open(file):
E       TypeError: expected str, bytes or os.PathLike object, not _io.StringIO

Considering the requirement for the input to be a text file, how can I best convert and use strings as input within the test method?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
trackness
  • 3
  • 4
  • 1
    If you want to test that a method opens a file, then you need to have at least one test that provides a file to see that the method opens it and returns something based on the contents. You can still separate the opening of the file from the iterating and the processing. You may need a helper class which can have different parts substituted when tests are being performed. Your `dunder` static method smells of a helper class wanting to be born. – quamrana Sep 13 '20 at 11:36
  • I'm not looking to avoid a test that takes an actual file (thus testing the file-accepting funtionality), more to have a (second, happily) test that will make testing the in-contents / out-contents much easier. I'd considered a helper method, but would like that to be a last resort, as it would mean adding functionality to support a test, which feels backwards (and isn't a requirement of the class). – trackness Sep 13 '20 at 11:45
  • You already have a help method. Better to have a helper class. Anyway you don't have to keep anything that helps pass the tests. Once the tests pass you can refactor the design into something else. – quamrana Sep 13 '20 at 11:47
  • I was unclear about the `__process_text_file()` method. The `# ...` signifies actual functionality specific to building the result. – trackness Sep 13 '20 at 11:53
  • Don't worry. That seemed quite clear to me. That was one of the things that contributed to my suggestion of a helper class. – quamrana Sep 13 '20 at 11:54

1 Answers1

0

This should work using StringIO

import io
input_file = io.StringIO(u"your text goes here") # takes unicode as argument

Dont break the string in multiple quoted separate strings instead try this -

"this\nthat"
a11apurva
  • 138
  • 10
  • Adding the `u` (and doing a qualified import, for completions's sake) did not seem to alter the exception given in my second attempted solution, unfortunately. The result persists with removal of the `\n` char. – trackness Sep 13 '20 at 11:45
  • You are right, the issue is that StringIO instance can't be passed to open() - use can try this [accepted solution](https://stackoverflow.com/questions/11892623/stringio-and-compatibility-with-with-statement-context-manager) to fake the file. – a11apurva Sep 13 '20 at 12:03
  • The solutions in the linked question gave me enough to build a test helper, thank you. – trackness Sep 13 '20 at 14:07