python mocking raw input in unittests
You can't patch input but you can wrap it to use mock.patch(). Here is a solution:
from unittest.mock import patch
from unittest import TestCase
def get_input(text):
return input(text)
def answer():
ans = get_input('enter yes or no')
if ans == 'yes':
return 'you entered yes'
if ans == 'no':
return 'you entered no'
class Test(TestCase):
# get_input will return 'yes' during this test
@patch('yourmodule.get_input', return_value='yes')
def test_answer_yes(self, input):
self.assertEqual(answer(), 'you entered yes')
@patch('yourmodule.get_input', return_value='no')
def test_answer_no(self, input):
self.assertEqual(answer(), 'you entered no')
Keep in mind that this snippet will only work in Python versions 3.3+
Mock a raw_input python
You should be able to mock __builtin__.raw_input
using whatever facilities you normally use to mock things.
A very simple example using unittest
and mock
looks like this:
import unittest
import mock
import __builtin__
def test_raw_input():
return raw_input()
class Test(unittest.TestCase):
@mock.patch.object(__builtin__, 'raw_input')
def test_stuff(self, mock_raw_input):
mock_raw_input.return_value = 7
self.assertEqual(test_raw_input(), 7)
unittest.main()
Using unittest.mock to patch input() in Python 3
__builtin__ module is renamed to builtins in Python 3. Replace as follow:
@patch('builtins.input', lambda *args: 'y')
UPDATE
input
has an optional parameter. updated the code to accept the optional parameter.
Is there a way to test methods with a lot of raw_input in django?
Simple answer: wraps each call to raw_input()
in distinct object that you can easily mock.
Unit Testing for user input and expected output in Python
You can make your main as a function that takes arguments instead.
def main(args):
...do stuff
if __name__ == '__main__':
args = input('Get input')
main(args)
Then just unittest it as a normal function.
class TestMain(unittest.TestCase):
def testmain(self):
self.assertTrue(main(5), 'foo')
If you still want to have the input within your main, then you need to mock patch input
not main
.
Python 3 Unit tests with user input
You can use mocking, where you replace a function or class with a test-supplied version. You can do this with the unittest.mock()
module.
In this case, you can patch the input()
name in your module; instead of the built-in function, the mock object will be called:
from unittest import mock
from unittest import TestCase
import module_under_test
class DictCreateTests(TestCase):
@mock.patch('module_under_test.input', create=True)
def testdictCreateSimple(self, mocked_input):
mocked_input.side_effect = ['Albert Einstein', '42.81', 'done']
result = dictCreate(1)
self.assertEqual(result, {'Albert Einstein': [42.81]})
Because input
doesn't exist in your module (it is a built-in function), I told the mock.patch()
decorator to create the name; now this input
will be used instead of the built-in function.
The side_effect
attribute lets you state multiple results; each time the mock is called, it'll return the next value in that list. So the first time 'Albert Einstein'
is returned, the next time '42.81'
, etc.
Together, this lets you simulate actual user inputs.
If you do your test right, you'll notice that there is a bug in your function; the float()
call will throw a ValueError
exception when anything other than done
or a valid numeric value is entered. You need to rework your code to account for that. Try with mocked_input.side_effect = ['Albert Einstein', 'Not an expense', '42.81', 'done']
to trigger the bug.
Unit testing a method with user input validations
You can use mock to mock a raw_input in Python and you can capture standard output by redirecting sys.stdout
to a StringIO
. This way you can mock your function input and test both invalid and valid cases:
import sys
import mock
import unittest
import StringIO
import __builtin__
# [..] your code
class Test(unittest.TestCase):
@mock.patch.object(__builtin__, 'raw_input')
def test_refreshtime_validation(self, mocked_raw_input):
my_stdout = StringIO.StringIO()
sys.stdout = my_stdout
mocked_raw_input.side_effect = ['error', '0', '1']
outputs = '\n**Please enter a valid number (Must be an integer).**\n'+\
'\n\n**Please enter a valid number (Must be greater than 0).**\n\n'
valid_value = refreshtime_validation()
sys.stdout = sys.__stdout__
self.assertEquals(my_stdout.getvalue(), outputs)
self.assertEquals(valid_value, 1)
unittest.main()
Related Topics
How to Set the Current Working Directory
How to Create Nested Dict in Python
Get Human Readable Version of File Size
In Python, How to Capture the Stdout from a C++ Shared Library to a Variable
Passing a Matplotlib Figure to HTML (Flask)
Generating HTML Documents in Python
Understand the Find() Function in Beautiful Soup
How Find Specific Data Attribute from HTML Tag in Beautifulsoup4
Using a Django Variable in a CSS File
Python Script for Minifying CSS
How to Edit Header Row in Pandas - Styling
How to Style Gtkbox Margin/Padding with CSS Only
Wtforms, Add a Class to a Form Dynamically
Python Image Library Fails with Message "Decoder Jpeg Not Available" - Pil
Pandas Groupby Range of Values