BankAccount.java

Download BankaAccount.java source file

/* Demo showing the use of assertions.  Assertions are best used for
 * implementation testing, usually by testing pre-condiitons,
 * post-conditions, and invariants.  (Note some pre-conditions are part
 * of the public interface, so assertions can't be used for them.  Instead
 * we test with if-statements and throw exceptions.)
 * 
 * Pre-conditions are tested at the beginning of methods and constructors,
 * post-conditions near the end.  Class invariants are tested at the end of
 * every public method and constructor.  That is the right way: inside of a
 * method it is allowed to temporarily violate a class invariant.
 * 
 * Also notice how implementation testing can overlap unit testing.  Many of
 * the assertions tested would also be tested by JUnit (black-box) tests.
 * 
 * This clase show a trivial bank account class.  It has an error (on purpose).
 * When run as "java BankAccount" it will crash with a strange-looking error.
 * To find the problem, run as "java -ea BankaAccount".  You should quickly
 * find the method with the error in it.
 *  
 * Written 10/2006 by Wayne Pollock, Tampa Florida USA
 */

public class BankAccount
{
    public static void main ( String [] args )
    {
        BankAccount myAccount = new BankAccount( 0.0 );
        myAccount.deposit( 500.00 );
        System.out.println( "Current balance is " + myAccount.getBalance() );
        myAccount.withdraw( 100.00 );
    }

    /** ********** Implementation starts here ********************* */

    /**
     * Class Invariant: balance >= 0.0
     */
    private double balance = 0.0;

    /**
     * Create a new bank account object, with some initial balance.
     * 
     * @param amount the amount to initially deposit
     * Pre-condition: initialBalance >= 0.0
     */
    public BankAccount ( double initialBalance )
    {
        if ( initialBalance < 0.0 )
            throw new IllegalArgumentException( "Initial balance ("
                    + initialBalance + ") must be >= 0" );

        balance = initialBalance;
        assert balance >= 0.0 : "invariant violation: balance = " + balance;
    }

    /**
     * @param amount the amount to deposit
     * Pre-condition: amount >= 0.0
     */
    public void deposit ( double amount )
    {
        if ( amount < 0.0 )
            throw new IllegalArgumentException( "Deposit amount (" + amount
                    + ") must be >= 0" );
        double newBalance = balance + amount;

        assert newBalance >= balance : "post-condition violation: new balance "
                + "(" + newBalance + ") < current balance (" + balance + ")";

        balance = newBalance;

        assert balance >= 0.0 : "invariant violation: balance = " + balance;
    }

    /**
     * @param amount the amount to deposit
     * Pre-condition: amount >= 0.0
     */
    public void withdraw( double amount )
    {
        if ( amount < 0.0 )
            throw new IllegalArgumentException( "Withdraw amount (" + amount
                    + ") must be >= 0" );

        if ( amount > balance )
            throw new IllegalArgumentException( "Withdraw amount (" + amount
                    + ") must be <= current balance (" + balance + ")" );
        balance -= amount;

        assert balance >= 0.0 : "invariant violation: balance = " + balance;
    }

    /**
     * @param amount the amount to deposit
     * Pre-condition: amount >= 0.0
     */
    public double getBalance ()
    {
        calculateInterest();

        assert balance >= 0.0 : "invariant violation: balance = " + balance;

        return balance;
    }

    /**
     * Post-condition: new balance >= old balance
     */
    private void calculateInterest ()
    {
        double newBalance = balance * .05;

        assert newBalance >= balance : "post-condition violation: new balance "
                + "(" + newBalance + ") < current balance (" + balance + ")";

        balance = newBalance;

        assert balance >= 0.0 : "post-condition violation: balance = " + balance;
    }
}