1

I have a console program written in Python. I would like to test several input combinations in an automatic test routine. The input is read via Pythons input(...) function.

  • How can I emulate a keyboard or any other input stream to send single characters or strings to input?
  • Or do I need to replace input by another function, which is connected to my test cases?
5
  • Look at unittest.mock. Commented Nov 27, 2016 at 21:45
  • 2
    Why not refactor such that you can call the actual functionality directly? Commented Nov 27, 2016 at 21:46
  • 1
    @jonrsharpe Because it's an integration test and no unit test :). Commented Nov 27, 2016 at 21:48
  • 1
    I'd suggest you mention integration testing in the question - in that case, you probably don't want to mock anything out. Commented Nov 27, 2016 at 22:19
  • 1
    I agree with @jonrsharpe. Unless input can (and will) only be called once in the entire system, mocking isn't the right way to go. Commented Nov 27, 2016 at 22:20

2 Answers 2

2

You can use unittest.mock to patch the output of a function (including streams).

#!/usr/bin/env python3

import unittest
from unittest.mock import patch

# Unit under test.
def get_input():
    my_input = input("Enter some string: ")
    if my_input == "bad":
        raise Exception("You were a bad boy...")
    return my_input

class MyTestCase(unittest.TestCase):
    # Force input to return "hello" whenever it's called in the following test
    @patch("builtins.input", return_value="hello")
    def test_input_good(self, mock_input):
        self.assertEqual(get_input(), "hello")

    # Force input to return "bad" whenever it's called in the following test
    @patch("builtins.input", return_value="bad")
    def test_input_throws_exception(self, mock_input):
        with self.assertRaises(Exception) as e:
            get_input()
            self.assertEqual(e.message, "You were a bad boy...")

if __name__ == "__main__":
    unittest.main()
Sign up to request clarification or add additional context in comments.

Comments

1

If that is just a test case and not a "real part of big system" - meaning that you just need to pass a certain input to your command line executable ones (e.g. run test) and you are using Unix, one convenient way of doing this is using pipes:

// read.py 
val = raw_input()
print 'nice', val

then via console:

$ echo "hat" | python read.py 
nice hat

on Windows syntax is little different - should be something like

dir> python.exe read.py < file.txt

One other hacky-simple way to achieve same thing is to replace sys.stdin with a custom stream object:

sys.stdin = StringIO.StringIO("line 1\nline 2\nline 3")

One should consider using @erip 's answer if that is something bigger than a automatisation routine or testing students' home assignments against fixed set of tests, though.

2 Comments

This isn't a very automated way to test software.
@erip, if you need to, let's say, test students home assignments against a fixed set of predefined tests, then why not? :) OP's original intent is not so clear. I fully agree that your solution should be used in real-world production

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.