Reputation: 158
In my unittest, I have 2 prompts in the test. I am trying to use 2 @patch("builtins.input")
, but it seems to only take the 1 of the return values.
@patch("builtins.input")
@patch("builtins.input")
def test_setProfileName_modify_init_prompt_empty(self, paramName1, paramName2):
paramName1.return_value = self.profileName_prod
paramName2.return_value = self.profileName_dev
a = c.ALMConfig(self.configType)
self.assertTrue(a.setProfileName())
self.assertEqual(a.getProfileName(), self.profileName_dev)
self.assertEqual(a.profileName, self.profileName_dev)
self.assertTrue(a.setProfileName())
self.assertEqual(a.getProfileName(), self.profileName_prod)
self.assertEqual(a.profileName, self.profileName_prod)
The call a.setProfileName()
will prompt for 1 input using input()
call in my function. In this test, it will call a.setProfileName()
twice.
a.setProfileName()
, I would enter the value of self.profileName_prod
.self.profileName_dev
.But the test fails after the second a.setProfileName()
case (at the second to last assertEqual
after the second a.setProfileName()
call).
self.assertEqual(a.getProfileName(), self.profileName_prod)
The reason for the failure is because a.getProfileName
is returning the value for self.profileName_dev
instead of self.profileName_prod
.
I had tested my code in the python cli to make sure the behavior is correct.
Any feedback is appreciated.
Thanks guys!
Upvotes: 3
Views: 3204
Reputation: 21
To provide a more simple and to the point answer for anyone visiting this in 2020 and later, you can just do
`with patch("builtins.input", return_value = "Whatever you want returned"):
self.assertEqual("<Object>", "Whatever you want returned")
`
in python 3.8 in later.
To see a full easy to follow example keep reading otherwise stop here.
Full Example: The below code shows a full example of this with a class named "AnsweredQuestion" and with a unit test
`class AnsweredQuestion:
def __init__(self):
print("I hope you find this example helpful")
def get_input(self):
print("Enter your input")
entered_data = input()
print("You entered '" + entered_data + "'")
return get_input
`
Unit Test to test above class AnsweredQuestion
`
import builtins
import unittest
import sys
sys.path.append(".")
# Assuming a directory named "answers" in your setup
import answers
from answers import AnsweredQuestion
from unittest.mock import Mock, patch
class TestAnsweredQuestion(unittest.TestCase):
def test_get_input(self):
with patch("builtins.input", return_value = "Thanks. This is correct"):
self.assertEqual(AnsweredQuestion.get_input(), "Thanks this is correct")
if __name__ == '__main__':
unittest.main()
`
Upvotes: 1
Reputation: 158
I revisited blhsing's solution, and it is more much elegant. Here is my working test code now:
@patch('builtins.input', side_effect=['dev', 'production'])
def test_setProfileName_modify_init_prompt_update_new(self, paramName):
a = c.ALMConfig(self.configType)
self.assertTrue(a.setProfileName())
self.assertEqual(a.getProfileName(), self.profileName_dev)
self.assertEqual(a.profileName, self.profileName_dev)
self.assertEqual(a.getProfileName(), self.profileName_dev)
self.assertTrue(a.setProfileName())
self.assertEqual(a.getProfileName(), self.profileName_prod)
self.assertEqual(a.profileName, self.profileName_prod)
Thanks everyone for your comments! :)
Upvotes: 1
Reputation: 107124
Patching the same function twice does not make it return different values on different calls. You can use the side_effect
attribute of the Mock
object by setting it with a list of values you want the function to return in successive calls instead:
from unittest.mock import patch
@patch('builtins.input', side_effect=['dev', 'prod'])
def test_input(mock_input):
assert input() == 'dev'
assert input() == 'prod'
test_input() # this will not raise an exception since all assertions are True
Upvotes: 5