0

I like TDD, so I try to write my Black Box Test at first.

This is a python programme that deal with stdin and output to stdout like this (I try to write my own language that just deal with stdin and stdout):

$ python3 ./minor.py
>>> print, "hello\nthis is a good morning"
... hello
  . this is a good morning
>>> $quit

But I can not mock the stdin and stdout. I try to use subprocess in Python but the Popen.stdout.read() is hanging for a EOF, which need the programme killed. Or the communicate() but it will kill my programme and it cannot deal with two or more input.

It upset me for 2+ days, I cannot find anything useful about mock or black-box test with stdin/stdout (It looks strange that I can test with browser but not stdin/stdout easily).

Thanks.

*** First Editing ***

I create a new unittest class to handle my class. It have a function to create a new Popen object.

I try to write to stdin and assert the stdout... But it is hanging just because it cannot find the EOF.

How should I deal with it to make it? Thanks for your help!

class TestFunc(unittest.TestCase):
    def run_minor(self):
        return Popen(['python3', './minor.py'],
                stdin = PIPE,
                stdout = PIPE,
                stderr = PIPE,
                text = True,
            )

    def test_print(self):
        prop = self.run_minor()

        self.assertEqual(prop.stdout.read(), '>>> ')

        prop.stdin.write("print, 'this'")
        self.assertEqual(prop.stdout.read(), '... this\n>>> ')

        prop.stdin.write("$quit")
        self.assertEqual(prop.stdout.read(), '')

        prop.kill()
7
  • I'm not sure I follow what you mean when you say you can't mock stdin and stdout -- sys.stdin and sys.stdout are just file-like objects, you can replace them with other file-like objects that behave however your tests require. There are cases in which you need to actually have overridden FD 0 and FD 1, but os.dup2() makes short work of those cases. Commented Aug 20, 2020 at 17:40
  • 2
    ...so, can you show us what you did to try to mock stdin or stdout, and an explicit failure mode you encountered in the attempt? Commented Aug 20, 2020 at 17:43
  • @CharlesDuffy OK, I am editing... Commented Aug 20, 2020 at 17:52
  • Does this answer your question? Python 3 unittest simulate user input Commented Aug 21, 2020 at 6:12
  • @Evgeny , No and yes... I am thinking because of your comment, and I can not mock it with another function! Just becuase I need to test it but not mock it. The thing that I want to mock is the input/output. By the way, I am thinking if use a function to handle input/output like a string is OK for me... input, then turn it to string and return a string, then output... Or build a class with state. Commented Aug 21, 2020 at 7:34

1 Answer 1

1

I create a helper class to help... I do not know if it is the best idea, but it works greatly:

class MinorMock(object):
    """
    The Mock of Minor Programme.

    Use method `input` and `assertOutput` to set the input and the output want. Use
    `assertInputMeetOutput` to check if the input is meet its output by unittest's object.
    """
    def __init__(self, test_obj):
        self.popen = Popen(['python3', 'minor.py'], stdin=PIPE, stdout=PIPE, stderr=PIPE, text=True)
        self.input_text = ''
        self.output_text = ''
        self.err_text = ''
        self.test_obj = test_obj

    def input(self, text):
        self.input_text += text
        return self

    def assertOutput(self, text):
        self.output_text += text
        return self

    def assertError(self, text):
        self.err_text += text
        return self
    
    def assertInputMeetOutput(self):
        (out, err) = self.popen.communicate(self.input_text)
        self.test_obj.assertEqual(out, self.output_text)
        self.test_obj.assertEqual(err, self.err_text)
        self.popen.kill()

Welcome for other answers...

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.