Skip to content

Instantly share code, notes, and snippets.

@metatoaster
Last active September 19, 2021 13:39
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save metatoaster/64139971b53ad728dba636e34b8a5558 to your computer and use it in GitHub Desktop.
Save metatoaster/64139971b53ad728dba636e34b8a5558 to your computer and use it in GitHub Desktop.
Simple Python unittest for mocking/stubbing sys.stdin and friends using native libs.
# -*- coding: utf-8 -*-
# To use, at the directory you saved this:
# python -m unittest test_stdio
import sys
import io
import unittest
def stub_stdin(testcase_inst, inputs):
stdin = sys.stdin
def cleanup():
sys.stdin = stdin
testcase_inst.addCleanup(cleanup)
sys.stdin = StringIO(inputs)
def stub_stdouts(testcase_inst):
stderr = sys.stderr
stdout = sys.stdout
def cleanup():
sys.stderr = stderr
sys.stdout = stdout
testcase_inst.addCleanup(cleanup)
sys.stderr = StringIO()
sys.stdout = StringIO()
class StdioTestCase(unittest.TestCase):
def test_example(self):
stub_stdin(self, '42')
stub_stdouts(self)
example()
self.assertEqual(sys.stdout.getvalue(), '42\n')
def helper(self, data, answer, runner):
stub_stdin(self, data)
stub_stdouts(self)
runner()
self.assertEqual(sys.stdout.getvalue(), answer)
# self.doCleanups() # optional, see comments below
def test_various_inputs(self):
data_and_answers = [
('hello', 'HELLOhello'),
('goodbye', 'GOODBYEgoodbye'),
]
runScript = upperlower # the function I want to test
for data, answer in data_and_answers:
self.helper(data, answer, runScript)
class StringIO(io.StringIO):
"""
A "safely" wrapped version
"""
def __init__(self, value=''):
value = value.encode('utf8', 'backslashreplace').decode('utf8')
io.StringIO.__init__(self, value)
def write(self, msg):
io.StringIO.write(self, msg.encode(
'utf8', 'backslashreplace').decode('utf8'))
def example():
number = raw_input()
print number.upper()
def upperlower():
raw = raw_input()
print (raw.upper() + raw),
# Calling doCleanup is optional simply because TestCase will call it by
# default. It's there to clean up instantly if it is desired and won't
# invoke other cleanup code prematurely.
@metatoaster
Copy link
Author

You're very welcome! (also apologies for getting your name wrong initially when doing the @ reply)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment