I have a simple ATM stimulating function in Pycharm and want to write tests for my functions. However every time I run my test on the first function asking for a User Pin, the terminal asks me for an input instead of running the mock. Here is my function:
def validate_pin(correct_pin):
pin_input = input('PLEASE ENTER YOUR 4-DIGIT PIN: ')
if pin_input.isnumeric() is True and int(pin_input) == correct_pin:
return True
return False
def calculate_balance(current_balance):
withdraw_amount = input("Please enter the amount you would like to withdraw: ")
if withdraw_amount.isnumeric() is not True:
raise TypeError
new_balance = current_balance - int(withdraw_amount)
if new_balance < 0:
raise Exception
return new_balance
def withdraw_money():
correct_pin = 1223
attempts = 3
balance = 100
while attempts != 0:
pin_validity = validate_pin(correct_pin)
if pin_validity is True:
print('PIN is correct.')
try:
new_balance = calculate_balance(balance)
except TypeError:
print("Please enter numbers only!")
except Exception:
print("You have put an unaccepted amount! Try again later.")
else:
print("You have £{} remaining in your account.".format(new_balance))
finally:
print("☻☻☻ THANK YOU FOR USING THIS ATM. HAVE A GOOD DAY! ☻☻☻")
break
else:
attempts -= 1
print("Wrong pin, try again! You only have {} attempts remaining.".format(attempts))
withdraw_money()
I have tried different versions of syntax to run the tests, non of which works ... Any thoughts?
1.
import unittest
from unittest.mock import patch
import atm
from unittest import TestCase
class TestingVersionThree(unittest, TestCase):
@patch('builtins.input', lambda *args: '1223')
def test_func1(self):
self.assertEqual(atm.validate_pin(), True)
@patch('builtins.input', lambda *args: '1111')
def test_func2(self):
self.assertEqual(atm.validate_pin(), False)
if __name__ == '__main__':
unittest.main()
class TestPinMockedInput(unittest.TestCase):
@patch('builtins.input', lambda x: "1223")
def test_with_valid_input(self):
result = atm.validate_pin()
expected_result = True
self.assertTrue(result == expected_result)
@patch('builtins.input', lambda x: "1111")
def test_invalid_input_wrong_number(self):
with self.assertRaises(ValueError):
result = atm.validate_pin()
expected_result = False
self.assertTrue(result == expected_result)
@patch('builtins.input', lambda x: "hi12")
def test_invalid_input_non_numeric(self):
with self.assertRaises(ValueError):
result = atm.validate_pin()
expected_result = False
self.assertTrue(result == expected_result)
if __name__ == '__main__':
unittest.main()
CodePudding user response:
When a Python file is imported, any code that is not in a function is executed. That means anything that is not indented is run.
When the unit test file does import atm
it will end up running the withdraw_money()
function call that is at the bottom of atm.py
.
The statement in file 2, if __name__ == "__main__":
, is the way of allowing the function to be executed if the file is run from the command line, but prevents the function being called if it is imported from another module.