pythoninputmocking

How can i mock user input in csv python


I want to mock add_new _costumer() in class NewCoustumer.

The filename is**: main.py**

import csv
import os

class NewCoustumer():
 def __init__(self,balance_checking = 0.0 , balance_saving = 0.0):
     self.balance_checking = balance_checking
     self.balance_saving = balance_saving
     if not os.path.exists("bank_data.csv") or os.stat("bank_data.csv").st_size == 0:
            with open("bank_data.csv", "w", newline="")as file:
                writer = csv.writer(file)
                writer.writerow(["account_id","first_name","last_name","password","balance_checking","balance_saving"])  

 def generate_account_id(self):
        try: 
            with open("bank_data.csv", "r")as file:
                reader = csv.reader(file)
                data = [row for row in reader if row and row[0].isdigit()]
                if len(data) > 1:
                    last_id = int(data[-1][0]) 
                    return str(last_id + 1)
                else:
                    return "10001"
        except FileNotFoundError:
            return "10001"
        
 def add_new_customer(self):
      account_id = self.generate_account_id()
      first_name = input("Enter first name: ")
      last_name = input("Enter last name: ")
      password = input("Enter password: ") 
      balance_checking = self.balance_checking
      balance_saving = self.balance_saving
    
      with open("bank_data.csv", mode='a', newline='') as file:
            writer = csv.writer(file)
            writer.writerow([account_id, first_name, last_name, password,balance_checking,balance_saving])
            return True

this is what i try to mock in another py page called: main_test.py

import unittest 
from unittest.mock import patch, Mock 
from main import NewCoustumer



class AddCustomer(unittest.TestCase, NewCoustumer):
    user_input = ['dan', 'sam','dan123']
    @patch('builtins.input', side_effect=[user_input])
    def test_add(self, mock_inputs):
        result = self.add_new_customer()
        self.assertTrue(result,True)

if __name__ == '__main__':
  unittest.main(verbosity=2 )

it shows this error :

(File "C:\Python313\Lib\unittest\mock.py", line 1171, in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "C:\Python313\Lib\unittest\mock.py", line 1228, in _execute_mock_call
    result = next(effect)
StopIteration)

Solution

  • The error is because your side_effect in the patch decorator is expecting 3 input calls, but you're providing a single list. Therefore, the mock tries to iterate through that list three times. When it reaches the end of the list, it tries to get the next element and throws the error.
    The correct code

    import unittest
    from unittest.mock import patch, Mock
    from main import NewCoustumer
    
    class TestAddCustomer(unittest.TestCase):
        def test_add(self):
            user_inputs = ['dan', 'sam', 'dan123']
            with patch('builtins.input', side_effect=user_inputs):
                customer = NewCoustumer()  # create an instance of NewCoustumer
                result = customer.add_new_customer()
                self.assertTrue(result)
    
    if __name__ == '__main__':
        unittest.main(verbosity=2)
    

    In your code AddCustomer are inheriting from both unittest.TestCase and NewCoustumer. The class now only inherits from unittest.TestCase and an instance of NewCoustumer is created inside the test method.