Python unit testing expected output from If Statement - python

I'm currently creating some unit test. I'm fairly new to them and just trying to get my feet wet. So the current test I'm trying to run is to check for an expected output according to the users input. So I would patch the input with some type of value and then check if I received the stdout message at the end. Sounds kind of confusing, but I hope some one can help. Here is my run code.
def main():
Attack = input("Are we being attacked?!")
if(Attack == "yes"):
print("We are being attacked! Attack Back!")
so in the above example I would test for the print statement since I would be patching the user input with the value of yes. Here is my test suite
import unittest
from unittest.mock import patch
import io
import sys
from RunFile import main
class GetInputTest(unittest.TestCase):
#patch('builtins.input', return_value='yes')
def test_output(self):
saved_stdout = sys.stdout
try:
out = io.StringIO()
sys.stdout = out
main()
output = out.getvalue().strip()
self.assertEqual(output, "We are being attacked! Attack Back!")
finally:
sys.stdout = saved_stdout
if __name__ == "__main__":
unittest.main()
So this obviously doesn't work. So what am I missing? Thank you all in advance!
EDITED: Here is the error message I get when I run the test. I understand the error, just don't know how I would go about fixing it.
Error
Traceback (most recent call last):
File "C:\Python33\lib\unittest\mock.py", line 1087, in patched
return func(*args, **keywargs)
TypeError: test_output() takes 1 positional argument but 2 were given

A function decorated by patch will take the Mock as an additional parameter. You need
#patch('builtins.input', return_value='yes')
def test_output(self, m):
where the second argument m will be a reference to the Mock object that replaces input when test_output is called.
From pydoc unittest.mock under patch:
If patch is used as a decorator and new is
omitted, the created mock is passed in as an extra argument to the
decorated function.

In addition to #chepner's answer, you'll need to use unittest.TestCase's assert methods rather than asserting yourself (pun intended)
class TestStuff(unittest.TestCase):
#patch('builtins.input', return_value='yes')
def test_output(self, new_input):
try:
out = io.StringIO()
sys.stdout = out
main()
output = out.getvalue().strip()
self.assertEqual(output, "We are being attacked! Attack Back!")
finally:
sys.stdout = saved_stdout
However that's probably not the best way to do what you're trying to do. You can patch more than one builtin, you know!
class TestStuff(unittest.TestCase):
#patch('builtins.input', return_value='yes')
#patch('builtins.print')
def test_output(self, new_print, new_input):
# the mocked functions are passed in opposite order
# to where they're decorated
main()
new_print.assert_called_with("We are being attacked! Attack Back!")
If the decorators are scary, you could even do:
class TestStuff(unittest.TestCase):
def test_output(self):
with patch('builtins.input', return_value='yes'), \
patch('builtins.print') as new_print:
main()
new_print.assert_called_with("We are being attacked! Attack Back!")

Related

Is it possible to run a single test method from a python unittest.TestCase with a reference to the method?

Suppose I have the following TestCase
class TestSomething(unittest.TestCase):
def test_a(self):
# Do some testing
def test_b(self):
# Do some other testing
Is it possible for me to run TestSomething.test_a if I have a reference to that test? What I am looking to do is something like:
def run_test(test):
# Somehow runs the test
# HERE IS THE PART I AM REALLY STUCK ON
run_test(TestSomething.test_a)
I know that it's an awkward thing to do for normal unit testing. What I am trying to do is provide a test to be run as an argument to a function decorator. Essentially:
#corresponding_test(TestSomething.test_a)
def my_function_a():
# Something here
And then in the decorator basically check if the test for that function passes before running the function.
OP clearly stated that the real world use case is more involved, but this still needs saying:
Disclaimer: This is not a good, standard way to run unit tests. If you use this code to run unit tests, you're [probably] doing it wrong.
That said, your question intrigued me, so I went ahead and wrote a working demo for you:
"""
The `only_if_test_passes` decorator can be used to run a function if and
only if the argument test (unbound `TestCase` method) passes.
"""
import inspect
from unittest import TestCase, TestResult
class TestError(Exception):
pass
class MyTests(TestCase):
def test_pass(self):
# This passes because nothing went wrong
pass
def test_fail(self):
self.fail('This test will always fail')
def only_if_test_passes(test_method):
# Comments are computed values when passed MyTests.test_pass
test_case_class = inspect._findclass(test_method) # MyTests
test_case_name = test_case_class.__name__ # 'MyTests'
test_name = test_method.__name__ # 'test_pass'
# Introspection for Python 2:
# test_case_class = test_method.im_class
# test_case_name = test_case_class.__name__ # Same as for Python 3
# test_name = test_method.if_func.func_name
def decorator(fn):
def decorated(*args, **kwargs):
test_result = TestResult()
case = test_case_class(test_name) # MyTests('test_pass')
case(test_result)
if test_result.wasSuccessful():
return fn(*args, **kwargs)
else:
raise TestError('Unit test failed: {}.{}'.format(
test_case_name, test_name))
return decorated
return decorator
#only_if_test_passes(MyTests.test_pass)
def this_will_run():
print('This should output')
#only_if_test_passes(MyTests.test_fail)
def this_wont_ever_run():
print("Don't bother; you'll never see this.")
if __name__ == "__main__":
this_will_run()
this_wont_ever_run()
gist
The introspection will be a little different in Python 2.
See also: unittest.TestCase docs

Python: Write unittest for console print

Function foo prints to console. I want to test the console print. How can I achieve this in python?
Need to test this function, has NO return statement :
def foo(inStr):
print "hi"+inStr
My test :
def test_foo():
cmdProcess = subprocess.Popen(foo("test"), stdout=subprocess.PIPE)
cmdOut = cmdProcess.communicate()[0]
self.assertEquals("hitest", cmdOut)
You can easily capture standard output by just temporarily redirecting sys.stdout to a StringIO object, as follows:
import StringIO
import sys
def foo(inStr):
print "hi"+inStr
def test_foo():
capturedOutput = StringIO.StringIO() # Create StringIO object
sys.stdout = capturedOutput # and redirect stdout.
foo('test') # Call unchanged function.
sys.stdout = sys.__stdout__ # Reset redirect.
print 'Captured', capturedOutput.getvalue() # Now works as before.
test_foo()
The output of this program is:
Captured hitest
showing that the redirection successfully captured the output and that you were able to restore the output stream to what it was before you began the capture.
Note that the code above in for Python 2.7, as the question indicates. Python 3 is slightly different:
import io
import sys
def foo(inStr):
print ("hi"+inStr)
def test_foo():
capturedOutput = io.StringIO() # Create StringIO object
sys.stdout = capturedOutput # and redirect stdout.
foo('test') # Call function.
sys.stdout = sys.__stdout__ # Reset redirect.
print ('Captured', capturedOutput.getvalue()) # Now works as before.
test_foo()
This Python 3 answer uses unittest.mock. It also uses a reusable helper method assert_stdout, although this helper is specific to the function being tested.
import io
import unittest
import unittest.mock
from .solution import fizzbuzz
class TestFizzBuzz(unittest.TestCase):
#unittest.mock.patch('sys.stdout', new_callable=io.StringIO)
def assert_stdout(self, n, expected_output, mock_stdout):
fizzbuzz(n)
self.assertEqual(mock_stdout.getvalue(), expected_output)
def test_only_numbers(self):
self.assert_stdout(2, '1\n2\n')
Note that the mock_stdout arg is passed automatically by the unittest.mock.patch decorator to the assert_stdout method.
A general-purpose TestStdout class, possibly a mixin, can in principle be derived from the above.
For those using Python ≥3.4, contextlib.redirect_stdout also exists, but it seems to serve no benefit over unittest.mock.patch.
If you happen to use pytest, it has builtin output capturing. Example (pytest-style tests):
def eggs():
print('eggs')
def test_spam(capsys):
eggs()
captured = capsys.readouterr()
assert captured.out == 'eggs\n'
You can also use it with unittest test classes, although you need to passthrough the fixture object into the test class, for example via an autouse fixture:
import unittest
import pytest
class TestSpam(unittest.TestCase):
#pytest.fixture(autouse=True)
def _pass_fixtures(self, capsys):
self.capsys = capsys
def test_eggs(self):
eggs()
captured = self.capsys.readouterr()
self.assertEqual('eggs\n', captured.out)
Check out Accessing captured output from a test function for more info.
You can also use the mock package as shown below, which is an example from
https://realpython.com/lessons/mocking-print-unit-tests.
from mock import patch
def greet(name):
print('Hello ', name)
#patch('builtins.print')
def test_greet(mock_print):
# The actual test
greet('John')
mock_print.assert_called_with('Hello ', 'John')
greet('Eric')
mock_print.assert_called_with('Hello ', 'Eric')
The answer of #Acumenus says:
It also uses a reusable helper method assert_stdout, although this helper is specific to the function being tested.
the bold part seems a big drawback, thus I would do the following instead:
# extend unittest.TestCase with new functionality
class TestCase(unittest.TestCase):
def assertStdout(self, expected_output):
return _AssertStdoutContext(self, expected_output)
# as a bonus, this syntactical sugar becomes possible:
def assertPrints(self, *expected_output):
expected_output = "\n".join(expected_output) + "\n"
return _AssertStdoutContext(self, expected_output)
class _AssertStdoutContext:
def __init__(self, testcase, expected):
self.testcase = testcase
self.expected = expected
self.captured = io.StringIO()
def __enter__(self):
sys.stdout = self.captured
return self
def __exit__(self, exc_type, exc_value, tb):
sys.stdout = sys.__stdout__
captured = self.captured.getvalue()
self.testcase.assertEqual(captured, self.expected)
this allows for the much nicer and much more re-usable:
# in a specific test case, the new method(s) can be used
class TestPrint(TestCase):
def test_print1(self):
with self.assertStdout("test\n"):
print("test")
by using a straight forward context manager. (It might also be desirable to append "\n" to expected_output since print() adds a newline by default. See next example...)
Furthermore, this very nice variant (for an arbitrary number of prints!)
def test_print2(self):
with self.assertPrints("test1", "test2"):
print("test1")
print("test2")
is possible now.
You can also capture the standard output of a method using contextlib.redirect_stdout:
import unittest
from contextlib import redirect_stdout
from io import StringIO
class TestMyStuff(unittest.TestCase):
# ...
def test_stdout(self):
with redirect_stdout(StringIO()) as sout:
my_command_that_prints_to_stdout()
# the stream replacing `stdout` is available outside the `with`
# you may wish to strip the trailing newline
retval = sout.getvalue().rstrip('\n')
# test the string captured from `stdout`
self.assertEqual(retval, "whatever_retval_should_be")
Gives you a locally scoped solution. It is also possible to capture the standard error using contextlib.redirect_stderr().
Another variant is leaning on the logging module rather than print(). This module also has a suggestion of when to use print in the documentation:
Display console output for ordinary usage of a command line script or program
PyTest has built-in support for testing logging messages.

Expecting Python assertRaises() to fail, but test always passes

I am attempting to get into the practice of TDD so I have been trying to start with Python's unittest module. I have written a test which I fully expect to fail, but it always passes! Below is the test code:
def test_file_not_found_exception(self):
invalid_config = "Testing/invalidExperiment.xml"
experiment_with_invalid_config = MyClass(invalid_config)
self.assertRaises(OSError, experiment_with_invalid_config.run_experiment())
and my class definition is as follows:
class MyClass:
def __init__(self, experiments, output_directory = ".")
self._experiments = experiments
self._output_directory = output_directory
def run_experiment(self):
try:
x = 2 # dummy statement
except OSError:
print "Experiment file not found"
except:
print "Unexpected Error"
I figure that the try block should always execute correctly so I am at a loss as to why my unittest keep passing. I am very new to OOP in Python so I may be making a very obvious mistake... Also, if I catch the exception in the try-except block of the run_experiment() method, should the assertRaises() call ever work?
You are calling the function MyClass.run_experiment and passing it's output to self.assertRaises, for which reason it does not properly register an error when it fails to raise.
Incorrect Example:
import unittest
class MyClass(object):
def __init__(self, config):
pass
def run_experiment(self): pass
class MainTest(unittest.TestCase):
def test_file_not_found_exception(self):
invalid_config = "Testing/invalidExperiment.xml"
experiment_with_invalid_config = MyClass(invalid_config)
self.assertRaises(OSError, experiment_with_invalid_config.run_experiment())
if __name__ == "__main__":
unittest.main()
Correct:
with self.assertRaises(OSError):
experiment_with_invalid_config.run_experiment()
Or
self.assertRaises(OSError, experiment_with_invalid_config.run_experiment)

How can I simulate input to stdin for pyunit?

I'm trying to test a function that takes input from stdin, which I'm currently testing with something like this:
cat /usr/share/dict/words | ./spellchecker.py
In the name of test automation, is there any way that pyunit can fake input to raw_input()?
The short answer is to monkey patch raw_input().
There are some good examples in the answer to How to display the redirected stdin in Python?
Here is a simple, trivial example using a lambda that throws away the prompt and returns what we want.
System Under Test
cat ./name_getter.py
#!/usr/bin/env python
class NameGetter(object):
def get_name(self):
self.name = raw_input('What is your name? ')
def greet(self):
print 'Hello, ', self.name, '!'
def run(self):
self.get_name()
self.greet()
if __name__ == '__main__':
ng = NameGetter()
ng.run()
$ echo Derek | ./name_getter.py
What is your name? Hello, Derek !
Test case:
$ cat ./t_name_getter.py
#!/usr/bin/env python
import unittest
import name_getter
class TestNameGetter(unittest.TestCase):
def test_get_alice(self):
name_getter.raw_input = lambda _: 'Alice'
ng = name_getter.NameGetter()
ng.get_name()
self.assertEquals(ng.name, 'Alice')
def test_get_bob(self):
name_getter.raw_input = lambda _: 'Bob'
ng = name_getter.NameGetter()
ng.get_name()
self.assertEquals(ng.name, 'Bob')
if __name__ == '__main__':
unittest.main()
$ ./t_name_getter.py -v
test_get_alice (__main__.TestNameGetter) ... ok
test_get_bob (__main__.TestNameGetter) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
Update -- using unittest.mock.patch
Since python 3.3 there is new submodule for unittest called mock that does exactly what you need to do. For those using python 2.6 or above there is a backport of mock found here.
import unittest
from unittest.mock import patch
import module_under_test
class MyTestCase(unittest.TestCase):
def setUp(self):
# raw_input is untouched before test
assert module_under_test.raw_input is __builtins__.raw_input
def test_using_with(self):
input_data = "123"
expected = int(input_data)
with patch.object(module_under_test, "raw_input", create=True,
return_value=expected):
# create=True is needed as raw_input is not in the globals of
# module_under_test, but actually found in __builtins__ .
actual = module_under_test.function()
self.assertEqual(expected, actual)
#patch.object(module_under_test, "raw_input", create=True)
def test_using_decorator(self, raw_input):
raw_input.return_value = input_data = "123"
expected = int(input_data)
actual = module_under_test.function()
self.assertEqual(expected, actual)
def tearDown(self):
# raw input is restored after test
assert module_under_test.raw_input is __builtins__.raw_input
if __name__ == "__main__":
unittest.main()
# where module_under_test.function is:
def function():
return int(raw_input("prompt> "))
Previous answer -- replacing sys.stdin
I think the sys module might be what you're looking for.
You can do something like
import sys
# save actual stdin in case we need it again later
stdin = sys.stdin
sys.stdin = open('simulatedInput.txt','r')
# or whatever else you want to provide the input eg. StringIO
raw_input will now read from simulatedInput.txt whenever it is called. If the contents of simulatedInput was
hello
bob
then the first call to raw_input would return "hello", the second "bob" and third would throw an EOFError as there was no more text to read.
You didn't describe what sort of code is in spellchecker.py, which gives me freedom to speculate.
Suppose it's something like this:
import sys
def check_stdin():
# some code that uses sys.stdin
To improve testability of check_stdin function, I propose to refactor it like so:
def check_stdin():
return check(sys.stdin)
def check(input_stream):
# same as original code, but instead of
# sys.stdin it is written it terms of input_stream.
Now most of your logic is in check function, and you can hand-craft whatever input you can imagine in order to test it properly, without any need to deal with stdin.
My 2 cents.
Replace sys.stdin with an instance of StringIO, and load the StringIO instance with the data you want returned via sys.stdin. Also, sys.__stdin__ contains the original sys.stdin object, so restoring sys.stdin after your test is as simple as sys.stdin = sys.__stdin__.
Fudge is a great python mock module, with convenient decorators for doing patching like this for you, with automatic cleanup. You should check it out.
If you are using mock module (written by Michael Foord), in order to mock raw_input function you can use syntax like:
#patch('src.main.raw_input', create=True, new=MagicMock(return_value='y'))
def test_1(self):
method_we_try_to_test(); # method or function that calls **raw_input**

Python and indentation, having trouble getting started.

I have just started learning python and am getting caught up. I come from mostly C background.
class Alarm:
def timer():
def main():
print ("Timer has Started")
main()
I always get a silly error when I try to run this code:
alarm > python alarm.py
File "alarm.py", line 5
def main():
^
IndentationError: expected an indented block
You have an empty def
def timer():
use
def timer():
pass
instead.
Learn about the pass statement, main is usually not part of the class.
A global (module level) main() function is simpler than an Alarm.main() class method. Usually, main() functions come at module level.
class Alarm:
def timer():
pass
def main():
print ("Timer has Started")
main()
I think you want to use __init__ though, which is the constructor...
class Alarm:
def timer(self):
print('timer has started')
def __init__(self):
print('constructor')
self.timer()
x = Alarm()
constructor
timer has started
My example differs from the others in that I'm actually instantiating a new object.
Notes:
specify self as the first argument to any method defined in the class
__init__ is the method to define for the constructor
invoke the class by doing variableName = className() like you would invoke a function, no new keyword
if you have an empty function, use the pass keyword like def foo(self): pass
Invoking main() will give an undefined function error, as it is a Alarm method.
IMHO the right form you should use is the following:
class Alarm:
def timer():
pass
#staticmethod
def main():
print ("Timer has Started")
if __name__ == "__main__" :
Alarm.main()
try deindent main() and add pass to timer and define an init method:
class Alarm():
def __init__(self):
print ("Timer has Started")
<shell>$ Alarm()
Your timer function is not defined. (And your space/tab indentation may be mixed)
See the tutorial (classes) for more details on classes.
class Alarm:
def timer(self):
pass
def main(self):
print ("Timer has Started")
if __name__ == '__main__':
class_inst = Alarm()
class_inst.main()
If you getting into python read PEP8.
Also, using pylint helps, it will point out indentation and many other errors you'll run across before you 'execute' your code.
As others have pointed out, you have a syntax error because timer() has no body.
You don't need to use main() in python at all. Usually people use it to indicate that the file is the top level program and not a module to be imported, but it is just by convention
You may also see this idiom
def main():
blah blah
if __name__ == "__main__":
main()
Here __name__ is a special variable. If the file has been imported it will contain the module name, so the comparison fails and main does not run.
For the top level program __name__ contains "__main__" so the main() function will be run.
This is useful because sometimes your module might run tests when it is loaded as a program but you don't want those test to run if you are importing it into a larger program
In Python, you don't need to define everything as a class. There's nothing to encapsulate in this code, so there's no reason to define an Alarm class. Just have the functions in a module.
Thanks for all the help everybody. I was making a little alarm/timer to remind me to get up and take a walk every now and then. I got most of it working, and it works great. Checked it against a stop watch and it works great.
import time
def timer(num):
seconds = num*60
print (num , "minutes", seconds , "seconds")
while (seconds > 0):
print (seconds, "seconds")
time.sleep(1)
seconds = seconds-1
print ("Time to get up and take a WALK!!!!")
main()
def main():
number = input("Input time : ")
int(number)
timer(number)
if __name__ == '__main__':
main()

Categories