diff --git a/abcbank/account.py b/abcbank/account.py index e010009..77da9fc 100644 --- a/abcbank/account.py +++ b/abcbank/account.py @@ -1,43 +1,118 @@ +from calendar import isleap +from datetime import date, timedelta from abcbank.transaction import Transaction -CHECKING = 0 -SAVINGS = 1 -MAXI_SAVINGS = 2 +def step(x): return x if x > 0 else 0; -class Account: - def __init__(self, accountType): - self.accountType = accountType - self.transactions = [] - def deposit(self, amount): - if (amount <= 0): - raise ValueError("amount must be greater than zero") - else: - self.transactions.append(Transaction(amount)) - def withdraw(self, amount): - if (amount <= 0): - raise ValueError("amount must be greater than zero") - else: - self.transactions.append(Transaction(-amount)) +def savings_rate_function_generator(account, tiers=[(0, 0.001), (1000, 0.002)]): + """ + Generator for interest calculation functions for a savings account. Interest is spread evenly over the days in a year + @todo determine whether we should be breaking down the interest into twelfths and dividing those over a month - def interestEarned(self): - amount = self.sumTransactions() - if self.accountType == SAVINGS: - if (amount <= 1000): - return amount * 0.001 + :param tiers: boundary values for interest rates + :type tiers: list of boundary, rate tuples, where the rate applies to values above the boundary + :return: a closure to calculate a day's interest given a transaction amount + """ + def savings_rate_function(amount, date): + tiers.sort() + balance = account.balance + interest = 0. + incremental_interest_rate = 0. + weighting = 0 + for tier in tiers: + # @todo should interest be spread evenly over the days in a year + # or evenly over the months and the days in each month? + if balance > tier[0]: + incremental_interest_rate = tier[1] - incremental_interest_rate + weighting += (balance - tier[0]) * incremental_interest_rate else: - return 1 + (amount - 1000) * 0.002 - if self.accountType == MAXI_SAVINGS: - if (amount <= 1000): - return amount * 0.02 - elif (amount <= 2000): - return 20 + (amount - 1000) * 0.05 - else: - return 70 + (amount - 2000) * 0.1 + break + effective_interest_rate = weighting/balance + days_in_year = 366. if isleap(date.year) else 365. + return amount * effective_interest_rate/days_in_year + + return savings_rate_function + + +def checking_rate_function_generator(account, rate=0.001): + # just use the savings rate function generator with one tier + return savings_rate_function_generator(account, [(0, rate),]) + + +def maxi_savings_rate_function_generator(account, usual_rate=0.05, for_span=timedelta(days=10), lowered_rate=0.001): + """ + + :rtype: float + """ + + def maxi_savings_rate_function(amount, date): + days_in_year = 366. if isleap(date.year) else 365. + # check for withdrawals trailing the interest date by less than the specified time frame + if [transaction for transaction in account._transactions if + transaction.amount < 0 and transaction.date.date() <= date and transaction.date.date() > date - for_span]: + rate = lowered_rate else: - return amount * 0.001 + rate = usual_rate + return amount * rate / days_in_year + + return maxi_savings_rate_function + + +rate_generator_by_account_type = { + 'Savings': savings_rate_function_generator + , 'Checking': checking_rate_function_generator + , 'Maxi Savings': maxi_savings_rate_function_generator +} + + +class Account: + """ + An Account is a list of transactions with a particular interest function generator + @todo Negative balances should probably incur some penalty + """ + + def __init__(self, account_type): + if account_type not in rate_generator_by_account_type: + raise StandardError('Unkown account type {account_type}'.format(account_type=account_type)) + self._transactions = [] + self.account_type = account_type + self.rate_function = rate_generator_by_account_type[account_type](self) + + def __str__(self): + transaction_litany = "\n".join([str(transaction) for transaction in self._transactions]) + total_summary = "Total ${:1.2f}".format(sum([t.amount for t in self._transactions])) + return ''' +{account_type} Account +{transaction_litany} +{total_summary} +'''.format(account_type=self.account_type, transaction_litany=transaction_litany, total_summary=total_summary) + + @property + def balance(self): + return sum([transaction.amount for transaction in self._transactions]) + + def append_transaction(self, amount, date = None): + self._transactions.append(Transaction(amount, self.rate_function, date)) + + def deposit(self, amount, date = None): + if (amount <= 0): raise ValueError("amount must be greater than zero") + self.append_transaction(amount, date) + + def withdraw(self, amount, date = None): + if (amount <= 0): raise ValueError("amount must be greater than zero") + self.append_transaction(-amount, date) + + def interest_earned(self, end_date = None): + """ + :param end_date: fix the date so crossing midnight while iterating doesn't break us + :type end_date: datetime.date + :return: interest earned on account through the specified date + """ + return sum([transaction.interest(end_date if end_date else date.today()) for transaction in self._transactions]) - def sumTransactions(self, checkAllTransactions=True): - return sum([t.amount for t in self.transactions]) \ No newline at end of file + @property + def statement(self): + return str(self) diff --git a/abcbank/bank.py b/abcbank/bank.py index 44711fe..258ff5e 100644 --- a/abcbank/bank.py +++ b/abcbank/bank.py @@ -1,25 +1,33 @@ +from datetime import date + +from abcbank.customer import Customer + class Bank: + ''' + A Bank is a list of Customers + ''' def __init__(self): self.customers = [] - def addCustomer(self, customer): + def add_customer(self, customer_name): + customer = Customer(customer_name) self.customers.append(customer) - def customerSummary(self): + return customer + + @property + def customer_summary(self): summary = "Customer Summary" for customer in self.customers: - summary = summary + "\n - " + customer.name + " (" + self._format(customer.numAccs(), "account") + ")" + summary = """{summary} + - {customer_name} ({account_count} account{s})""".format(summary = summary + , customer_name = customer.name + , account_count = len(customer.accounts) + , s = 's' if len(customer.accounts) - 1 else '') return summary - def _format(self, number, word): - return str(number) + " " + (word if (number == 1) else word + "s") - def totalInterestPaid(self): - total = 0 - for c in self.customers: - total += c.totalInterestEarned() - return total - def getFirstCustomer(self): - try: - self.customers = None - return self.customers[0].name - except Exception as e: - print(e) - return "Error" \ No newline at end of file + + @property + def total_interest_paid(self, end_date = None): + if end_date is None: + end_date = date.today() + return sum(sum([account.interest_earned(end_date) + for account in customer.accounts]) for customer in self.customers) diff --git a/abcbank/customer.py b/abcbank/customer.py index 7cfd62a..1198e37 100644 --- a/abcbank/customer.py +++ b/abcbank/customer.py @@ -1,55 +1,74 @@ -from account import CHECKING, SAVINGS, MAXI_SAVINGS +from abcbank.account import Account, rate_generator_by_account_type class Customer: + ''' + A Customer is a list of Accounts with a Name + ''' + def __init__(self, name): - self.name = name self.accounts = [] + self.name = name - def openAccount(self, account): - self.accounts.append(account) - return self + def __str__(self): + statement = "Statement for %s\n" % self.name + for account in self.accounts: + statement = '%s%s' % (statement, account) + statement = '''{0:s} +Total In All Accounts ${1:1.2f}'''.format(statement + , sum([sum([transaction.amount for transaction in account._transactions]) + for account in self.accounts])) + return statement - def numAccs(self): - return len(self.accounts) + def open_account(self, account_type, initial_transaction_amount=0, initial_transaction_date = None): + """ - def totalInterestEarned(self): - return sum([a.interestEarned() for a in self.accounts]) + :type initial_transaction_amount: float + """ + account = Account(account_type) + self.accounts.append(account) + if initial_transaction_amount > 0: + account.deposit(initial_transaction_amount, initial_transaction_date) + elif initial_transaction_amount < 0: + account.withdraw(-initial_transaction_amount, initial_transaction_date) + return account - # This method gets a statement - def getStatement(self): - # JIRA-123 Change by Joe Bloggs 29/7/1988 start - statement = None # reset statement to null here - # JIRA-123 Change by Joe Bloggs 29/7/1988 end - totalAcrossAllAccounts = sum([a.sumTransactions() for a in self.accounts]) - statement = "Statement for %s" % self.name - for account in self.accounts: - statement = statement + self.statementForAccount(account) - statement = statement + "\n\nTotal In All Accounts " + _toDollars(totalAcrossAllAccounts) - return statement + def transfer(self, from_account_type, to_account_type, amount): + ''' + Go through accounts of a particular type, finding enough money to cover the transfer. Move that money to an + abitrary customer account of the specified account type, creating a new account if required - def statementForAccount(self, account): - accountType = "\n\n\n" - if account.accountType == CHECKING: - accountType = "\n\nChecking Account\n" - if account.accountType == SAVINGS: - accountType = "\n\nSavings Account\n" - if account.accountType == MAXI_SAVINGS: - accountType = "\n\nMaxi Savings Account\n" - transactionSummary = [self.withdrawalOrDepositText(t) + " " + _toDollars(abs(t.amount)) - for t in account.transactions] - transactionSummary = " " + "\n ".join(transactionSummary) + "\n" - totalSummary = "Total " + _toDollars(sum([t.amount for t in account.transactions])) - return accountType + transactionSummary + totalSummary - - def withdrawalOrDepositText(self, transaction): - if transaction.amount < 0: - return "withdrawal" - elif transaction.amount > 0: - return "deposit" + :param from_account_type: Account type to debit + :param to_account_type: Account type to credit + :param amount: Amount + :except: StandardError with message 'Insufficient funds: ${balance:f1.2} available; ${request:f1.2} requested' + :except: AttributeError with message 'Invalid account type {account_type}' + :return: credited account + ''' + for account_type in (from_account_type, to_account_type): + if account_type not in rate_generator_by_account_type: + raise StandardError('Invalid account type {account_type}'.format(account_type=account_type)) + available = sum([account.balance for account in self.accounts if account.account_type == from_account_type]) + if available < amount: + raise StandardError( + 'Insufficient funds: ${available:1.2f} available; ${amount:1.2f} requested'.format( + available=available, amount=amount)) + remaining = amount + for account in [acct for acct in self.accounts if acct.account_type == from_account_type]: + if account.balance >= remaining: + account.withdraw(remaining) + remaining = 0 + break + else: + remaining -= account.balance + account.withdraw(account.balance) + if to_account_type in [acct.account_type for acct in self.accounts]: + account = [acct for acct in self.accounts if acct.account_type == to_account_type][0] else: - return "N/A" - + account = self.open_account(to_account_type) + account.deposit(amount) + return account -def _toDollars(number): - return "${:1.2f}".format(number) + @property + def statement(self): + return str(self) diff --git a/abcbank/date_provider.py b/abcbank/date_provider.py deleted file mode 100644 index 33b64eb..0000000 --- a/abcbank/date_provider.py +++ /dev/null @@ -1,7 +0,0 @@ -from datetime import datetime - - -class DateProvider: - @staticmethod - def now(): - return datetime.now() \ No newline at end of file diff --git a/abcbank/transaction.py b/abcbank/transaction.py index 8e5b5ad..bb12674 100644 --- a/abcbank/transaction.py +++ b/abcbank/transaction.py @@ -1,7 +1,52 @@ -from datetime import datetime +from datetime import datetime, date, timedelta -class Transaction: - def __init__(self, amount): +class Transaction(object): + """ + A Transaction is an amount of money at a time that accrues according to a closure + """ + + def __init__(self, amount, interest_function = lambda y, z: 0, date=None): + """ + + :param amount: Value of transaction -- positive for deposits, negative for withdrawals + :param interest_function: function that returns an amount of interest given a balance and a date. Defaults to returning 0 + :type interest_function: function + :param date: effective date of transaction from which interest is calculated + :type date: datetime.datetime + :return: + """ self.amount = amount - self.transactionDate = datetime.now() \ No newline at end of file + self.date = date if date else datetime.now() + self.interest_function = interest_function + + def __str__(self): + return " {withdrawal_or_deposit} {amount}".format( + withdrawal_or_deposit='withdrawal' if self.amount < 0 else 'deposit' + , amount="${:1.2f}".format(abs(self.amount))) + + + def __repr__(self): + return '{str} at {date}'.format(str=str(self).strip(), date=self.date) + + + def interest(self, end_date = None): + """ + Calculates the transaction's compound interest by applying the account's interest function to this transaction + from the transaction date to the prior date (ie, not today) + + :param end_date: date through which to calculate interest + :type end_date: datetime.date + :return: interest payable due to this transaction + """ + balance = self.amount + # range give an empty list for any negative number, so we don't have to compare end_date to self.date + ''' + This was an unexpected little Python 3 change + 'end_date if end_date else date.today() - self.date.date()' from my Python 2.7 code now gets interpreted as + 'end_date if end_date else (date.today() - self.date.date())', which of course breaks this. So, now I have + '(end_date if end_date else date.today()) - self.date.date()' + ''' + for delta in range(((end_date if end_date else date.today()) - self.date.date()).days): + balance += self.interest_function(balance, self.date.date() + timedelta(days = delta)) + return balance - self.amount \ No newline at end of file diff --git a/tests/bank_tests.py b/tests/bank_tests.py deleted file mode 100644 index 6de98db..0000000 --- a/tests/bank_tests.py +++ /dev/null @@ -1,38 +0,0 @@ -from nose.tools import assert_equals - -from account import Account, CHECKING, MAXI_SAVINGS, SAVINGS -from bank import Bank -from customer import Customer - - -def test_customer_summary(): - bank = Bank() - john = Customer("John").openAccount(Account(CHECKING)) - bank.addCustomer(john) - assert_equals(bank.customerSummary(), - "Customer Summary\n - John (1 account)") - - -def test_checking_account(): - bank = Bank() - checkingAccount = Account(CHECKING) - bill = Customer("Bill").openAccount(checkingAccount) - bank.addCustomer(bill) - checkingAccount.deposit(100.0) - assert_equals(bank.totalInterestPaid(), 0.1) - - -def test_savings_account(): - bank = Bank() - checkingAccount = Account(SAVINGS) - bank.addCustomer(Customer("Bill").openAccount(checkingAccount)) - checkingAccount.deposit(1500.0) - assert_equals(bank.totalInterestPaid(), 2.0) - - -def test_maxi_savings_account(): - bank = Bank() - checkingAccount = Account(MAXI_SAVINGS) - bank.addCustomer(Customer("Bill").openAccount(checkingAccount)) - checkingAccount.deposit(3000.0) - assert_equals(bank.totalInterestPaid(), 170.0) \ No newline at end of file diff --git a/tests/customer_tests.py b/tests/customer_tests.py deleted file mode 100644 index 0211a4f..0000000 --- a/tests/customer_tests.py +++ /dev/null @@ -1,36 +0,0 @@ -from nose.tools import assert_equals, nottest - -from account import Account, CHECKING, SAVINGS -from customer import Customer - - -def test_statement(): - checkingAccount = Account(CHECKING) - savingsAccount = Account(SAVINGS) - henry = Customer("Henry").openAccount(checkingAccount).openAccount(savingsAccount) - checkingAccount.deposit(100.0) - savingsAccount.deposit(4000.0) - savingsAccount.withdraw(200.0) - assert_equals(henry.getStatement(), - "Statement for Henry" + - "\n\nChecking Account\n deposit $100.00\nTotal $100.00" + - "\n\nSavings Account\n deposit $4000.00\n withdrawal $200.00\nTotal $3800.00" + - "\n\nTotal In All Accounts $3900.00") - - -def test_oneAccount(): - oscar = Customer("Oscar").openAccount(Account(SAVINGS)) - assert_equals(oscar.numAccs(), 1) - - -def test_twoAccounts(): - oscar = Customer("Oscar").openAccount(Account(SAVINGS)) - oscar.openAccount(Account(CHECKING)) - assert_equals(oscar.numAccs(), 2) - - -@nottest -def test_threeAccounts(): - oscar = Customer("Oscar").openAccount(Account(SAVINGS)) - oscar.openAccount(Account(CHECKING)) - assert_equals(oscar.numAccs(), 3) \ No newline at end of file diff --git a/tests/test_account.py b/tests/test_account.py new file mode 100644 index 0000000..121b578 --- /dev/null +++ b/tests/test_account.py @@ -0,0 +1,71 @@ +from nose.tools import assert_almost_equal, assert_equal, assert_raises + +from abcbank.account import Account +from abcbank.bank import Bank +from abcbank.transaction import Transaction +from calendar import isleap +from datetime import datetime, timedelta +from math import pow + + +def test_transactions(): + account = Bank().add_customer('Kavita').open_account('Savings', 5) + assert_equal([transaction.amount for transaction in account._transactions], [5,]) + account.withdraw(5) + assert_equal([transaction.amount for transaction in account._transactions], [5, -5,]) + +def test_statement(): + account = Bank().add_customer('Praveen').open_account('Checking', 5) + account.withdraw(4) + assert_equal(account.statement, """ +Checking Account + deposit $5.00 + withdrawal $4.00 +Total $1.00 +""") + + +def test_type_constraint(): + assert_raises(StandardError, Account, 'Cheeseburger') + +def test_interest(): + account = Bank().add_customer('Penelope').open_account('Maxi Savings') + account.deposit(5000, datetime.today() - timedelta(2)) + expected_interest = 5000*(pow(1 + 50./365000, 2) - 1) + assert_almost_equal(expected_interest, account.interest_earned()) + account.withdraw(4000, datetime.today() - timedelta(1)) + # one day of 5 % interest on $5000 + expected_interest = 5000*(pow(1 + 50./365000, 1) - 1) + # one day of 1 mil interest on $1000 + expected_interest += (1000 + expected_interest)*(pow(1 + 1./365000, 1) - 1) + # @todo this blows up at midnight, as another day's interest gets added + assert_almost_equal(expected_interest, account.interest_earned()) + + account = Bank().add_customer('Dick').open_account('Maxi Savings') + account.deposit(5000, datetime.today() - timedelta(16)) + expected_interest = 5000*(pow(1 + 50./365000, 16) - 1) + assert_almost_equal(expected_interest, account.interest_earned()) + account.withdraw(4000, datetime.today() - timedelta(15)) + # one day of 5 % interest on $5000 + expected_interest = 5000*(pow(1 + 50./365000, 1) - 1) + # ten days of 1 mil interest on $1000 + earned interest + expected_interest += (1000 + expected_interest)*(pow(1 + 1./365000, 10) - 1) + # five days of 5 % interest on $1000 + earned interest + expected_interest += (1000 + expected_interest)*(pow(1 + 50./365000, 5) - 1) + assert_almost_equal(expected_interest, account.interest_earned()) + + # check interest over one year against the interest function + + one_year_ago = datetime.now() - timedelta(365) # the leap day can cause an error up to about 1/3 % + + checking_account = Bank().add_customer('Xinqi').open_account('Checking', 1000, one_year_ago) + expected_interest = 1000*(pow(1 + 1./365000, 365) - 1) + assert_almost_equal(expected_interest, checking_account.interest_earned()) + + savings_account = Bank().add_customer('Yong').open_account('Savings', 5000, one_year_ago) + # one fifth is at 0.001, four-fifths is at 0.002, so 0.0018 is the rate + expected_interest = 5000*(pow(1 + 1.8/365000, 365) - 1) + assert_almost_equal(expected_interest, savings_account.interest_earned()) + + + diff --git a/tests/test_bank.py b/tests/test_bank.py new file mode 100644 index 0000000..27d2467 --- /dev/null +++ b/tests/test_bank.py @@ -0,0 +1,54 @@ +# coding=utf-8 +import logging +from nose.tools import assert_equals, assert_almost_equal + +from abcbank.bank import Bank + +from datetime import datetime, timedelta +from math import pow + + +def test_customer_summary(): + bank = Bank() + bank.add_customer('John').open_account('Checking') + assert_equals("Customer Summary\n - John (1 account)", bank.customer_summary) + +def test_interest(): + """ + @todo These tests cannnot go to Production without making them robust to leap years, which you could do simply by + turning down the precision on assert_almost_equals: keeping the precision would require pretty rococo test code + + """ + bank = Bank() + one_year_ago = datetime.today() - timedelta(days = 365) + two_years_ago = one_year_ago - timedelta(days = 365) + + # first customer with checking account + bank.add_customer("Bill").open_account('Checking', 100.0, two_years_ago) # 10 ยข interest + expected_interest = 100* (pow(1 + 1./365000, 730) - 1) + assert_almost_equal(expected_interest, bank.total_interest_paid) + + # second customer with savings account + bank.add_customer("Jill").open_account('Savings', 1500.0, one_year_ago) # $2 interest + expected_interest += 1500 * (pow(1 + (4./3)/365000, 365) - 1) + assert_almost_equal(expected_interest, bank.total_interest_paid) + + # third customer with maxi savings account + phil = bank.add_customer("Phil") + maxi_savings_account = phil.open_account('Maxi Savings', 3000, datetime.today() - timedelta(days = 30)) + expected_interest_plus_30_days_maxi = expected_interest + 3000 * (pow(1 + 50./365000, 30) - 1) + assert_almost_equal(expected_interest_plus_30_days_maxi, bank.total_interest_paid) + + # third customer's maxi savings account suffers a withdrawal + maxi_savings_account.withdraw(2000, datetime.today() - timedelta(days = 20)) + # 3000@10 days maxi interest, 1000@10 days mini interest, 1000@10 days maxi interest + maxi_interest = 3000 * (pow(1 + 50./365000, 10) - 1) + maxi_interest += (1000 + maxi_interest) * (pow(1 + 1./365000, 10) - 1) + maxi_interest += (1000 + maxi_interest) * (pow(1 + 50./365000, 10) - 1) + expected_interest += maxi_interest + assert_almost_equal(expected_interest, bank.total_interest_paid) + + # third customer has two accounts + phil.open_account('Checking', 100.0, datetime.today() - timedelta(days = 30)) + expected_interest += 100* (pow(1 + 1./365000, 30) - 1) + assert_almost_equal(expected_interest, bank.total_interest_paid) \ No newline at end of file diff --git a/tests/test_customer.py b/tests/test_customer.py new file mode 100644 index 0000000..2ffd6ac --- /dev/null +++ b/tests/test_customer.py @@ -0,0 +1,51 @@ +from nose.tools import assert_equals, assert_raises_regexp + +from abcbank.bank import Bank + + +def test_statement(): + henry = Bank().add_customer("Henry") + henry.open_account('Checking', 100) + henry.open_account('Savings', 4000).withdraw(200.0) + assert_equals(henry.statement, + "Statement for Henry" + + "\n\nChecking Account\n deposit $100.00\nTotal $100.00" + + "\n\nSavings Account\n deposit $4000.00\n withdrawal $200.00\nTotal $3800.00" + + "\n\nTotal In All Accounts $3900.00") + + +def test_open_account(): + oscar = Bank().add_customer("Oscar") + oscar.open_account('Savings') + oscar.open_account('Checking') + oscar.open_account('Maxi Savings') + assert_equals(len(oscar.accounts), 3) + + +def test_transfer(): + holly = Bank().add_customer('Holly') + holly.open_account('Savings', 2500) + holly.open_account('Maxi Savings', 3000) + # blow up if there are insufficient funds in the only account of a type + assert_raises_regexp(StandardError, r'Insufficient funds: [$]2500.00 available; [$]3000.00 requested' + , holly.transfer, 'Savings', 'Checking', 3000) + second_savings_account = holly.open_account('Savings', 300) + # blow up if there are insufficient funds in all accounts of a type + assert_raises_regexp(StandardError, r'Insufficient funds: [$]2800.00 available; [$]3000.00 requested' + , holly.transfer, 'Savings', 'Checking', 3000) + second_savings_account.deposit(200) + checking_account = holly.transfer('Savings', 'Checking', 3000) + # Successful transfer into a new account + assert_equals(''' +Checking Account + deposit $3000.00 +Total $3000.00 +''', checking_account.statement) + # Successful transfer into an existing account + holly.transfer('Maxi Savings', 'Checking', 3000) + assert_equals('Statement for Holly\n\nSavings Account\n deposit $2500.00\n withdrawal $2500.00\nTotal $0.00\n\nMaxi Savings Account\n deposit $3000.00\n withdrawal $3000.00\nTotal $0.00\n\nSavings Account\n deposit $300.00\n deposit $200.00\n withdrawal $500.00\nTotal $0.00\n\nChecking Account\n deposit $3000.00\n deposit $3000.00\nTotal $6000.00\n\nTotal In All Accounts $6000.00', str(holly)) + + # blow up if either the from or two account types are not recognized + assert_raises_regexp(StandardError, 'Invalid account type Fandango', holly.transfer, 'Fandango', 'Checking', 1) + assert_raises_regexp(StandardError, 'Invalid account type Fandango', holly.transfer, 'Checking', 'Fandango', 1) + diff --git a/tests/test_transaction.py b/tests/test_transaction.py new file mode 100644 index 0000000..179640f --- /dev/null +++ b/tests/test_transaction.py @@ -0,0 +1,18 @@ +from nose.tools import assert_equal, assert_less_equal +import logging; + +from abcbank.transaction import Transaction +from datetime import datetime, timedelta + + +def test_instance_parameters(): + now = datetime.now() + transaction = Transaction(5) + assert_less_equal(transaction.date - now, timedelta(milliseconds=1), 'transaction booked at create date') + assert_equal(transaction.amount, 5, 'transaction reflects specified value of 5') + + +def test_statement(): + transaction = Transaction(-5) + logging.info(str(transaction)) + assert_equal(' withdrawal $5.00', str(transaction)) \ No newline at end of file diff --git a/tests/transaction_tests.py b/tests/transaction_tests.py deleted file mode 100644 index 62caa8a..0000000 --- a/tests/transaction_tests.py +++ /dev/null @@ -1,8 +0,0 @@ -from nose.tools import assert_is_instance - -from transaction import Transaction - - -def test_type(): - t = Transaction(5) - assert_is_instance(t, Transaction, "correct type") \ No newline at end of file