Python Mocking Raw Input in Unittests

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



Leave a reply



Submit