No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Pruebas de Registro de Transacciones en Cuentas Bancarias

6/20
Recursos

El método teardown es esencial para asegurar que nuestras pruebas no interfieran entre sí, y se usa para limpiar cualquier recurso temporal al final de cada prueba. En este caso, lo hemos aplicado a nuestra cuenta bancaria, donde se registra un log cada vez que se realiza una acción. Vamos a explorar cómo implementarlo correctamente y agregar funcionalidades de logging a nuestra cuenta de banco.

¿Qué es el método teardown y cuándo lo usamos?

El método teardown se ejecuta al final de cada prueba, y es utilizado para limpiar recursos como archivos temporales o cerrar conexiones. En este caso, lo usamos para eliminar el archivo de logs que se genera durante nuestras pruebas de la cuenta bancaria. De esta manera, cada prueba se ejecuta en un entorno limpio, sin interferencias de pruebas anteriores.

¿Cómo agregamos logging a la cuenta de banco?

Añadimos una funcionalidad de logging en el método init, el cual se ejecuta cada vez que se crea una instancia de nuestra clase BankAccount. El log incluye eventos como la creación de la cuenta, la consulta de saldo, y cuando se realizan depósitos o retiros. Esto se realiza a través del método logTransaction, que escribe el mensaje en un archivo de texto.

  • Se define un archivo de log (logFile) al crear la cuenta.
  • Cada vez que se realiza una transacción o se consulta el saldo, se agrega una línea al archivo.
  • Para asegurar que el archivo de log se genera correctamente, creamos pruebas automatizadas.

¿Cómo validamos la existencia del archivo de log?

En nuestras pruebas, verificamos si el archivo de log se crea exitosamente. Utilizamos la función os.path.exists para validar su existencia y asegurarnos de que nuestras pruebas están funcionando correctamente.

¿Cómo usamos el teardown para limpiar archivos?

El teardown nos permite eliminar el archivo de log después de cada prueba para que no interfiera con otras. Implementamos una función que, si el archivo existe, lo borra utilizando os.remove. Esto asegura que las pruebas se ejecutan en un entorno limpio y los logs no se acumulan entre pruebas.

¿Cómo probamos que los logs contienen la información correcta?

Además de verificar que el archivo existe, es fundamental asegurarnos de que el contenido del archivo sea correcto. Para ello, creamos un método que cuenta las líneas del archivo (countLines). Luego, en nuestras pruebas, validamos que el número de líneas corresponde al número de transacciones realizadas.

  • Contamos las líneas después de crear la cuenta (debe haber una línea).
  • Hacemos un depósito y volvemos a contar las líneas (debe haber dos líneas).
  • Si no limpiáramos el archivo con teardown, el número de líneas sería incorrecto.

¿Cómo crear una nueva funcionalidad de logging para transferencias fallidas?

El siguiente reto es agregar una funcionalidad para registrar un log cuando alguien intente hacer una transferencia sin saldo disponible. El log debe incluir un mensaje indicando la falta de fondos, y también se deben crear pruebas que validen que este log se genera correctamente.

  • Se debe registrar el intento fallido en el archivo de log.
  • Crear una prueba para asegurarse de que el mensaje “No tiene saldo disponible” aparece en el log.
  • Utilizar teardown para limpiar el archivo al finalizar cada prueba.

Aportes 12

Preguntas 0

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Aca mi codigo del reto. junto con el reto de la clase pasada este se volvió muy sencillo. Nota: Se comentaron dos funciones para poder validar que el código funciona de la manera deseada haciendo que se escriba un error para que el unittest de positivo solo hay que modificar el monto a transferir ```python class BankAccount: def __init__(self, balance = 0, log_file = None): self.balance = balance self.log_file = log_file self._log_transaction("Cuenta creada") def _log_transaction(self,message): if self.log_file: with open(self.log_file, "a") as f: f.write(f"{message}\n") def deposit(self, amount): if amount > 0: self.balance += amount self._log_transaction(f"Cantidad depositada {amount}. Nuevo balance: {self.balance}") return self.balance def withdraw(self, amount): if amount > 0: self.balance -= amount self._log_transaction(f"Retiro {amount}. Nuevo balance: {self.balance}") return self.balance def transfer(self, amount, target_account): if amount > 0 and self.balance >= amount: self.balance -= amount target_account.deposit(amount) else: self._log_transaction(f"Transferencia fallida por monto {amount}. Saldo disponible {self.balance}") raise ValueError("No tienes saldo suficiente para transferir") return self.balance def get_balance(self): self._log_transaction(f"Revision de balance. Balance actual {self.balance}") return self.balance ``````python import unittest import os from src.bank_account import BankAccount class BankAccountTest(unittest.TestCase): def setUp(self) -> None: self.account = BankAccount(balance = 1000, log_file = "transaction_log.txt") self.target_account = BankAccount(balance=500) """def tearDown(self) -> None: if os.path.exists(self.account.log_file): os.remove(self.account.log_file)""" def _count_lines(self, filename): with open(filename, "r") as f: return len(f.readlines()) def test_deposit(self): new_balance = self.account.deposit(500) assert new_balance == 1500 def test_withdraw(self): new_balance = self.account.withdraw(500) assert new_balance == 500 def test_transfer(self): self.account.transfer(20000, self.target_account) self.assertEqual(self.account.get_balance(), 800) self.assertEqual(self.target_account.get_balance(), 700) def test_get_balance(self): assert self.account.get_balance() == 1000 def test_transaction_log(self): self.account.deposit(500) assert os.path.exists("transaction_log.txt") """def test_count_transactions(self): assert self._count_lines(self.account.log_file) == 1 self.account.deposit(500) assert self._count_lines(self.account.log_file) == 2""" ```
RETO: Agrega un log cada vez que alguien intenta hacer una transferencia y no tenga saldo disponible. Crear dos pruebas que validen que el texto es el correcto, y limpiar tus archivos de prueba una vez que hayas hecho todas las pruebas.
comparto mi solución, que emoción * módulo bank\_account.py ![](https://static.platzi.com/media/user_upload/image-ab35577b-16d4-4567-a8e1-8df7bf1e9b0b.jpg) * módulo test\_bank\_account.py ![](https://static.platzi.com/media/user_upload/image-3f1a5033-549b-43c0-9479-3b2c85fbbaf8.jpg)
Comparto mi solución al reto: Bank class ```js class BankAccount: def __init__(self, balance=0, log_file=None): self.balance = balance self.log_file = log_file self._log_transaction('Cuenta creada') def _log_transaction(self, message): if self.log_file: with open(self.log_file, "a") as f: f.write(f"{message}\n") def deposit(self, amount): if amount > 0: self.balance += amount self._log_transaction(f"Deposited {amount}. New balance: {self.balance}") return self.balance def withdraw(self, amount): if amount > 0: self.balance -= amount self._log_transaction(f"Withdrew {amount}. New balance: {self.balance}") return self.balance def get_balance(self): self._log_transaction(f"Checked balance. Current balance: {self.balance}") return self.balance def transfer(self, current_balance, amount_send, destination_account): if current_balance >= amount_send: destination_account.deposit(amount_send) self.withdraw(amount_send) else: self._log_transaction(f"No tiene saldo disponible") return "No se puede realizar la trasnferencia saldo insuficiente" return self.get_balance() ```Test class ```python import unittest, os from src.bank_account import BankAccount class BankAccountTests(unittest.TestCase): #Queda pendiente una tarea #El método setup se ejecuta antes de cualquier prueba y se puede usar para centralizar el código repetido y compartido entre las funciones de prueba def setUp(self): self.account = BankAccount(balance=1000, log_file="transaction_log.txt") #Método que se ejecuta al finalizar las pruebas def tearDown(self): if os.path.exists(self.account.log_file): os.remove(self.account.log_file) def _count_lines(self, filename): with open(filename, "r") as f: return len(f.readlines()) def _read_lines(self, filename, text_compare): with open(filename, "r") as f: for line in f: if text_compare.strip() in line.strip(): return True return False def test_deposit(self): new_balance = self.account.deposit(500) assert new_balance == 1500 def test_withdraw(self): new_balance = self.account.withdraw(200) assert new_balance == 800 def test_get_balance(self): assert self.account.get_balance() == 1000 def test_transfer(self): current_balance = self.account.get_balance() destination_account = BankAccount(balance=2000) amount_send = 500 assert self.account.transfer(current_balance, amount_send, destination_account) == 500 def test_transfer_no_balance(self): current_balance = 0 destination_account = BankAccount(balance=2000) amount_send = 500 assert self.account.transfer(current_balance, amount_send, destination_account) == "No se puede realizar la trasnferencia saldo insuficiente" def test_trasnfer_log_no_balance(self): current_balance = 0 destination_account = BankAccount(balance=2000) amount_send = 500 self.account.transfer(current_balance, amount_send, destination_account) assert self._read_lines(self.account.log_file,"No tiene saldo disponible") == True #Ya funciona def test_transaction_log(self): self.account.deposit(500) assert os.path.exists("transaction_log.txt") def test_count_transactions(self): assert self._count_lines(self.account.log_file) == 1 self.account.deposit(500) assert self._count_lines(self.account.log_file) == 2 ```
```python def transfer(self, account, amount): if 0 < amount <= self.balance: self.balance -= amount account.deposit(amount) self.log_transaction(f"new Transfer of {amount} succeeded") return self.balance self.log_transaction(f"new Transfer of {amount}") raise ValueError("Invalid transfer amount") ``````python def test_transfer(self): account2 = BankAccount(500) self.account.transfer(account2, 500) assert self.account.get_balance() == 500 assert account2.get_balance() == 1000 assert self.count_lines(self.account.log_file) == 2 def test_transfer_fail(self): with self.assertRaises(ValueError): account2 = BankAccount(500) self.account.transfer(account2, 2000) assert self.count_lines(self.account.log_file) == 2 ```
Comparto mi solución al reto:def transfer(self, amount):        # Transferir una cantidad de la cuenta si es mayor que 0 y menor o igual al saldo        if amount > 0 and amount <= self.balance:            self.balance -= amount            self.\_log\_transaction(f'Transferencia de {amount}. Saldo actual: {self.balance}')        else:            self.\_log\_transaction(f'Transferencia fallida. Saldo insuficiente')            raise ValueError('Saldo insuficiente')                    return self.balance ```js def transfer(self, amount): # Transferir una cantidad de la cuenta si es mayor que 0 y menor o igual al saldo if amount > 0 and amount <= self.balance: self.balance -= amount self._log_transaction(f'Transferencia de {amount}. Saldo actual: {self.balance}') else: self._log_transaction(f'Transferencia fallida. Saldo insuficiente') raise ValueError('Saldo insuficiente') return self.balance def test_transfer_log(self): with self.assertRaises(ValueError): self.account.transfer(5000) assert self.count_lines() == 2 ```
```python def transaction(self, amount): if amount > 0 and self.balance < amount: self._log_transaction("Transaction Failed. Not enough funds in the account.") raise ValueError("Transaction Failed. Not enough funds in the account.") elif amount > 0 and self.balance > amount: self.balance -= amount return self.balance /////////////////// def _last_line(self, filename): with open(filename, "r") as f: lines = f.readlines() return lines[-1].strip() def test_transaction_ValueError_logText(self): with self.assertRaisesRegex(ValueError, "Transaction Failed. Not enough funds in the account."): self.account.transaction(1100) assert self._last_line(self.account.log_file) == "Transaction Failed. Not enough funds in the account." ```    def transaction(self, amount):        if amount > 0 and self.balance < amount:            self.\_log\_transaction("Transaction Failed. Not enough funds in the account.")            raise ValueError("Transaction Failed. Not enough funds in the account.")        elif amount > 0 and self.balance > amount:            self.balance -= amount            return self.balance
Función para transferir: ```python def transfer(self, amount, account): if self.balance <= amount: self._log_transaction("Insufficient balance") raise ValueError("Insufficient balance") if amount < 0: self._log_transaction("Amount must be greater than zero") raise ValueError("Amount must be greater than zero") self.withdraw(amount) self._log_transaction( f"Transferred {amount} to {account}. New balance: {self.balance}" ) account.deposit(amount) return self.balance ```def transfer(self, amount, account):        if self.balance <= amount:            self.\_log\_transaction("Insufficient balance")            raise ValueError("Insufficient balance")        if amount < 0:            self.\_log\_transaction("Amount must be greater than zero")            raise ValueError("Amount must be greater than zero")        self.withdraw(amount)        self.\_log\_transaction(            f"Transferred {amount} to {account}. New balance: {self.balance}"        )        account.deposit(amount)        return self.balance `Test:` ```js def test_insufficient_balance(self): account2 = BankAccount(balance=500) with self.assertRaises(ValueError): self.account.transfer(3000, account2) ```    def test\_insufficient\_balance(self):        account2 = BankAccount(balance=500)        with self.assertRaises(ValueError):            self.account.transfer(3000, account2)
Hola a todos, dejo el código del reto ```js from __future__ import annotations class BankAccount: def __init__(self, balance=0, log_file=None): self.balance = balance self.log_file = log_file self._log_transaction("Cuenta creada") def _log_transaction(self,message): if self.log_file: # abre el archivo en modo append with open(self.log_file,"a") as f: f.write(f"{message}\n") def deposit(self, amount): if amount > 0: self.balance += amount self._log_transaction(f"Deposited {amount}. New balance: {self.balance}") return self.balance def withdraw(self, amount): if amount > 0: self.balance -= amount self._log_transaction(f"Withdrew {amount}. New balance: {self.balance}") return self.balance def get_balance(self): self._log_transaction(f"Checked balance. Current balance: {self.balance}") return self.balance def transfer(self, amount, account: BankAccount): if self.balance < amount: self._log_transaction(f"Insuficient Balance: {self.balance} - Amount: {amount}") raise ValueError("Balance insuficiente") account.deposit(amount) return self.withdraw(amount) ```
EL reto: ```python class BankAccount: def __init__(self, balance=0, log_file=None): self.balance = balance self.log_file = log_file self._log_transaction('Cuenta creada') def _log_transaction(self, message): if self.log_file: with open(self.log_file, "a") as f: f.write(f'{message}\n') def _log_not_funds(self, message): if self.log_file: with open(self.log_file, "a") as f: f.write(f'{message}\n') def deposit(self, amount): if amount > 0: self.balance += amount self._log_transaction(f'Deposited {amount}. New balance: {self.balance}') return self.balance def withdraw(self, amount): if amount > 0: self.balance -= amount self._log_transaction(f'Withdraw {amount}. New balance: {self.balance}') return self.balance def get_balance(self): self._log_transaction(f'Current balance: {self.balance}') return self.balance def transfer(self, amount, account_number): if amount > self.balance: self._log_not_funds("Sin fondos suficiente para la transferencia") raise InsufficientFunds("No tienes fondos para realizar esta transferencia") elif len(account_number) < 10: raise AccountNumberNotValid("El número de cuenta debe de ser mayor o igual a 10 dígitos") else: self.balance -= amount self._log_transaction(f'Transferido {amount}. Nuevo saldo: {self.balance}') return f'Se transfirió la cantidad {amount} al número de cuenta {account_number}. El balance de la cuenta es {self.balance}' class InsufficientFunds(Exception): def __init__(self, mensaje): self.mensaje = mensaje super().__init__(self.mensaje) class AccountNumberNotValid(Exception): def __init__(self, mensaje): self.mensaje = mensaje super().__init__(self.mensaje) #tests import unittest from src.bank_account import BankAccount import os class BankAccount_test(unittest.TestCase): def setUp(self) -> None: self.account = BankAccount(1000, log_file="transaction_log.txt") def tearDown(self) -> None: if os.path.exists(self.account.log_file): os.remove(self.account.log_file) def _count_lines(self, filename): with open(filename, "r") as r: return len(r.readlines()) def test_deposit(self): balance = self.account.deposit(500) self.assertEqual(balance, 1500) def test_withdraw(self): balance = self.account.withdraw(500) self.assertEqual(balance, 500) def test_get_balance(self): balance = self.account.get_balance() self.assertEqual(balance, 1000) def test_transfer(self): result = self.account.transfer(500, '12345678901') self.assertEqual(result, f'Se transfirió la cantidad 500 al número de cuenta 12345678901. El balance de la cuenta es 500') def test_transfer_transfer(self): self.account.transfer(200, "222222223333444444") self.assertTrue(os.path.exists("transaction_log.txt")) def test_transaction_log(self): self.account.deposit(500) self.assertTrue(os.path.exists("transaction_log.txt")) def test_count_transctions(self): assert self._count_lines(self.account.log_file) == 1 self.account.transfer(200, "222222223333444444") assert self._count_lines(self.account.log_file) == 2 ```class BankAccount: def \_\_init\_\_(self, balance=0, log\_file=None): self.balance = balance self.log\_file = log\_file self.\_log\_transaction('Cuenta creada') def \_log\_transaction(self, message): if self.log\_file: with open(self.log\_file, "a") as f: f.write(f'{message}\n') def \_log\_not\_funds(self, message): if self.log\_file: with open(self.log\_file, "a") as f: f.write(f'{message}\n') def deposit(self, amount): if amount > 0: self.balance += amount self.\_log\_transaction(f'Deposited {amount}. New balance: {self.balance}') return self.balance def withdraw(self, amount): if amount > 0: self.balance -= amount self.\_log\_transaction(f'Withdraw {amount}. New balance: {self.balance}') return self.balance def get\_balance(self): self.\_log\_transaction(f'Current balance: {self.balance}') return self.balance def transfer(self, amount, account\_number): if amount > self.balance: self.\_log\_not\_funds("Sin fondos suficiente para la transferencia") raise InsufficientFunds("No tienes fondos para realizar esta transferencia") elif len(account\_number) < 10: raise AccountNumberNotValid("El número de cuenta debe de ser mayor o igual a 10 dígitos") else: self.balance -= amount self.\_log\_transaction(f'Transferido {amount}. Nuevo saldo: {self.balance}') return f'Se transfirió la cantidad {amount} al número de cuenta {account\_number}. El balance de la cuenta es {self.balance}' class InsufficientFunds(Exception): def \_\_init\_\_(self, mensaje): self.mensaje = mensaje super().\_\_init\_\_(self.mensaje) class AccountNumberNotValid(Exception): def \_\_init\_\_(self, mensaje): self.mensaje = mensaje super().\_\_init\_\_(self.mensaje)
En la función para transferir, agregué un `if` y un `else`, si el monto es menor a la cantidad en el balance arroja el mensaje de "Fondos insuficientes". ```python # ----- Código con las funciones ----- class BankAccount: def __init__(self, balance=0, log_file=None): self.balance = balance self.log_file = log_file self._log_transaction('Cuenta creada') def _log_transaction(self, message): if self.log_file: with open(self.log_file, "a") as f: f.write(f"{message}\n") def deposit(self, amount): if amount > 0: self.balance += amount self._log_transaction(f"Deposited {amount}. New balance: {self.balance}.") return self.balance def withdraw(self, amount): if amount > 0: self.balance -= amount self._log_transaction(f"Withdrew {amount}. New balance: {self.balance}.") return self.balance def get_balance(self): self._log_transaction(f"Checked balance. Current balance {self.balance}.") return self.balance def transfer(self, amount): if self.balance >= amount: self.balance = self.balance - amount self._log_transaction(f"Transfered {amount}. New balance: {self.balance}.") else: self._log_transaction(f"Not transfered {amount}. Insufficient founds: {self.balance}") print("Fondos insuficientes.") return self.balance # ----- Código de las pruebas ----- import unittest import os from src.bank_account import BankAccount class BankAccountTests(unittest.TestCase): # Con seUp lo que se hace es definir desde el inicio los valores que tendrán las funciones. # Es una manera de evitar escribir los valores iniciales desde el inicio, en este caso,todas las variables iniciarán con $1,000 # def setUp(self) -> None: self.account = BankAccount(balance=1000, log_file="transaction_log.txt") def tearDown(self) -> None: if os.path.exists(self.account.log_file): os.remove(self.account.log_file) def _count_lines(self, filename): with open(filename, "r") as f: return len(f.readlines()) def test_deposit(self): new_balance = self.account.deposit(500) assert new_balance == 1500 def test_withdraw(self): new_balance = self.account.withdraw(200) assert new_balance == 800 def test_get_balance(self): assert self.account.get_balance() == 1000 def test_transfer(self): new_balance = self.account.transfer(1700) assert new_balance == 1000 def test_transaction_log(self): new_balance = self.account.deposit(500) assert os.path.exists("transaction_log.txt") def test_count_transactions(self): assert self._count_lines(self.account.log_file) == 1 self.account.deposit(500) assert self._count_lines(self.account.log_file) == 2 ```
Mi solución resumida solo para el reto: * En la clase BankAccout utilizo un rase ValueError. ```js def transfer(self,amount: int, target): if amount > 0 and self.balance > amount: target.deposit(amount) self.balance -= amount return self.balance else: self._log_transaction(f"You can not perfomece this action. Balance {self.balance}") raise ValueError('You do not have enough money') ``` * Para poder capturar el mensaje de texto a la hora de realizar el text utilizo assertRaises(ValueError). En el test me debo asegurar que pongo el mismo mensaje que lanzo en la clase. ```js def test_insufficient_funds_transfer(self): target = BankAccount(balance=500) with self.assertRaises(ValueError) as context: self.account.transfer(2000, target) self.assertEqual(str(context.exception), "You do not have enough money") ```