import unittest from datetime import datetime from unittest.mock import MagicMock, AsyncMock from decimal import Decimal from src.ez_lan_manager.services.AccountingService import AccountingService, InsufficientFundsError from src.ez_lan_manager.types.Transaction import Transaction class AccountingServiceTests(unittest.IsolatedAsyncioTestCase): def setUp(self) -> None: self.mock_database_service = MagicMock() self.mock_database_service.add_transaction = AsyncMock() self.accounting_service = AccountingService(self.mock_database_service) def test_importing_unit_under_test_works(self) -> None: """ This test asserts that the object produced in setUp is AccountingService object, if that fails, there is no reason to execute any other test. """ self.assertIsInstance(self.accounting_service, AccountingService) def test_making_string_from_euro_value_works_correctly(self) -> None: test_value = Decimal("134.66") expected_result = "134.66 €" self.assertEqual(expected_result, AccountingService.make_euro_string_from_decimal(test_value)) def test_making_euro_string_from_negative_value_works_correctly(self) -> None: test_value = Decimal("-997.41") expected_result = "-997.41 €" self.assertEqual(expected_result, AccountingService.make_euro_string_from_decimal(test_value)) def test_making_euro_string_from_less_than_ten_cents_works_correctly(self) -> None: test_value = Decimal("0.04") expected_result = "0.04 €" self.assertEqual(expected_result, AccountingService.make_euro_string_from_decimal(test_value)) async def test_get_balance_correctly_adds_up_transactions(self) -> None: self.mock_database_service.get_all_transactions_for_user = AsyncMock(return_value=[ Transaction( user_id=0, value=Decimal("0.05"), is_debit=True, reference="", transaction_date=datetime.now() ), Transaction( user_id=0, value=Decimal("0.99"), is_debit=False, reference="", transaction_date=datetime.now() ), Transaction( user_id=0, value=Decimal("1.01"), is_debit=False, reference="", transaction_date=datetime.now() ), Transaction( user_id=0, value=Decimal("0.77"), is_debit=True, reference="", transaction_date=datetime.now() ), ]) expected_result = Decimal("1.18") actual_result = await self.accounting_service.get_balance(0) self.assertEqual(expected_result, actual_result) async def test_trying_to_remove_more_than_is_on_account_balance_raises_exception(self) -> None: user_balance = Decimal("1.00") balance_to_remove = Decimal("1.01") self.mock_database_service.get_all_transactions_for_user = AsyncMock(return_value=[ Transaction( user_id=0, value=user_balance, is_debit=False, reference="", transaction_date=datetime.now() ) ]) with self.assertRaises(InsufficientFundsError): await self.accounting_service.remove_balance(0, balance_to_remove, "TestRef") async def test_trying_to_remove_less_than_is_on_account_balance_spawns_correct_transaction(self) -> None: user_balance = Decimal("1.01") balance_to_remove = Decimal("1.00") reference = "Yey, a reference" self.mock_database_service.get_all_transactions_for_user = AsyncMock(return_value=[ Transaction( user_id=123, value=user_balance, is_debit=False, reference="", transaction_date=datetime.now() ) ]) await self.accounting_service.remove_balance(123, balance_to_remove, reference) # Async unittest API is still not perfect for retrieving a call value. So we force it to hand it over. last_transaction: Transaction = self.mock_database_service.add_transaction.call_args_list[-1].args[-1] self.assertEqual(123, last_transaction.user_id) self.assertEqual(balance_to_remove, last_transaction.value) self.assertEqual(True, last_transaction.is_debit) self.assertEqual(reference, last_transaction.reference)