For practicing designing systems I created a simple bank ATM system.
I didn't want to make it to complicated so I left out things like cash bin per ATM and opening cash trays, etc. I also wanted to neglect APIs to validate pins, etc. (it's just a function that will always return True). I wanted to focus on classes and methods.
So in my example I have
Accountclass which has an account number, a balance and withdraw and deposit functions.
Cardclass which has accounts and a select account function which will search for the account number on the card and then return it.
ATMclass which has the following variables:
current_cardand the main function are
perform_request(which will either give out the balance, deposit or withdraw money),
validate_pin(which will make the call to the API, mocked in my code),
select_account(which will select an account from the card)
I did write a test for it and it worked. I was wondering if I could get some feedback on that (not the test, I know I can do lot's of things to make the tests better but that was just a quick and dirty version of it)?
def validate_api(card_nr, pin): # validate account nr and pin # return true or fale return True class Card(): def __init__(self, accounts = ): self.accounts = accounts def select_account(self, account_nr): # check if there is a built in filter func in python for account in self.accounts: if account.account_nr == account_nr: return account raise Exception("Account number invalid") class Account(): def __init__(self, account_nr = None): self.account_nr = account_nr self.balance = 0 def deposit(self, amount): self.balance += amount def withdraw(self, amount): self.balance -= amount class ATM(): def __init__(self): self.card_inserted = False self.card_validated = False self.current_account = None self.current_card = None def validate_card_and_pin(self): if not self.card_inserted: raise Exception('Card must be inserted first') if self.card_validated is False: raise Exception # raise Exception("Card not validated") def insert_card(self, bank_card): # code to accept card self.card_inserted = True self.current_card = bank_card def eject_card(self): self.end_session() # code to push card out def validate_pin(self, pin): if not self.card_inserted: raise Exception('Card must be inserted first') # card is inserted, pin has to be validated # post pin and card number to api # response will be saved in validated variable validated = validate_api(card_nr=0,pin=0) if validated == False: self.card_validated = False return self.card_validated self.card_validated = True return self.card_validated def select_account(self, account_nr): self.validate_card_and_pin() if self.current_card is None: raise Exception("no card in ATM") if self.card_validated is False: raise Exception("card not validated") current_account = self.current_card.select_account(account_nr) self.current_account = current_account ''' 1 = check balance 2 = deposit money 3 = withdraw money ''' def perform_request(self, request, amount = 0): self.validate_card_and_pin() if request == 1: return self.check_balance() elif request == 2: return self.accept_cash(amount) elif request == 3: return self.give_out_cash(amount) else: raise Exception("invalid request") def accept_cash(self, amount): # open cash tray # count cash self.current_account.deposit(amount) return amount def give_out_cash(self, amount): # count cash # open tray self.current_account.withdraw(amount) return amount def check_balance(self): return self.current_account.balance def end_session(self): self.card_inserted = False self.card_validated = False self.current_account = None self.current_card = None return True
And here the test:
def test_depositing_50_and_withdrawing_20(): checking = Account(1) saving = Account(2) bank_card = Card([checking, saving]) atm = ATM() atm.insert_card(bank_card) atm.validate_pin("123") atm.select_account(1) atm.perform_request(2, 50) if atm.perform_request(1) is not 50: raise Exception("depositing function doesn't work") atm.end_session() atm.insert_card(bank_card) atm.validate_pin("123") atm.select_account(1) atm.perform_request(3, 20) if atm.perform_request(1) is not 30: raise Exception("withdrawing function doesn't work") atm.select_account(2) atm.validate_pin("123") atm.perform_request(2, 10) if atm.perform_request(1) is not 10: raise Exception("depositing function doesn't work") print("Test successful")