Click to See Complete Forum and Search --> : Help with test Application


gammaman
May 6th, 2008, 08:59 AM
Hi, I need help writing a test application for my program. I have three files an Account Class which is a super class, and two sub classes, one being a checking account and the other a savings account. I need to write a test application to test the methods of the two subclasses. I am very new to java and I am a little confused about how to test all of the methods properly. Here are the three classes followed by what I have so far in the test application.

The super class

public class Account {
private String firstName;
private String lastName;
private double balance;
private Date estDate;
private static int count=0; //number of objects in memory

//constructor to initialize first and last name, Date object and balance
public Account(String first, String last, Date eDate, double bal) {
firstName = first;
lastName = last;
balance = bal;
estDate = eDate;
count++;

}
//method to add amount to balance
public void credit(double amount){
balance+=amount;
} //end of method credit

//method to subtract amount from balance
public boolean debit(double amount){
if (amount > balance)
{
//prevents user from overwithdrawing from their account
return false;
}
else
{
balance -= amount;
return true;
}
} //end of method debit

//displays the current balance in the account
public double getBalance() {
return balance;
}

//method to set the balance to the account
public void setBalance(double balance) {
this.balance = balance;
}

//method to get the number of accounts
public static int getCount() {
return count;
} //end of method getCount

//method to get the date using date object class
public Date getDate() {
return estDate;
} //end of method getDate

// method to format the output in the form of a String
public String toString(){
return String.format("%s,%s\t%s\t%5.2f\n",lastName,firstName,estDate,balance);
} //end of method toString
} //end of class Account


Subclass checking account

public class CheckingAccount extends Account{
private double transactionFee;

public CheckingAccount( String first, String last, Date edate,double bal, double fee){
super(first,last,edate,bal);
transactionFee=fee;
}
//set the credit
public void credit(double amount){
super.credit(amount);
chargeFee();
}
//set the debit
public boolean debit(double amount){
if(super.debit(amount)){
chargeFee();
return true;
}
return false;
}
//output the fee
public String toString(){
return String.format(super.toString() + "Fee:" + transactionFee);

}

private void chargeFee(){
setBalance(getBalance()-transactionFee);
System.out.println("Fee Charged" + transactionFee);

}

}


subclass savings account

public class SavingsAccount extends Account{
private double interestRate;

public SavingsAccount(String first,String last, Date edate,double bal, double rate){
super(first,last,edate,bal);
interestRate=rate;
}
//set the calculated interest
public double calculateInterest(){
return getBalance()*interestRate;
}
//print out the calculated interest
public String toString(){
return String.format(super.toString() +"Interest:" +calculateInterest());

}
}



The test application


public class AccountTest {

public static void main(String[] args){
Date aDate = new Date( 7, 24, 1949 );
Account account=new Account("Bob","Power",aDate,2000.0);
CheckingAccount cAccount=new CheckingAccount("John","Doe",aDate,5000.0,10.0);
SavingsAccount sAccount=new SavingsAccount("Sarah","Black",aDate,6000.0,0.05);
account.toString();
account.debit(1000);
account.toString();
account.credit(500);
System.out.format("Balance: %5.2f\n",account.getBalance());
account.setBalance(4000);
System.out.format("New Balance: %5.2f\n",account.getBalance());
System.out.format("Date: %10s\n",account.getDate());


cAccount.debit(2000);

cAccount.credit(200);


sAccount.debit(2000);

sAccount.credit(200);

System.out.format("Current interest: %5.2f\n",sAccount.calculateInterest());
}

}

dlorde
May 6th, 2008, 09:56 AM
Your test code should instantiate each class and individually test every available (i.e. public) action of the class, comparing the actual result with the expected result. Each test should be independent of the others.

For example, when you create an account, you should immediately test that the values that come out when you cal the 'get' methods are the same as the values you passed in. You should also test that invalid values are correctly rejected (e.g. -ve values, null values, very large values, etc). You should check that getBalance() returns the same value as you set with setBalance(). You should check that debit(..) correctly returns false if the debit is larger than the balance, that it returns true if the debit is valid and that the balance is reduced the correct amount, and that it handles invalid or null values correctly, etc., etc.

Once you've tested all the individual actions possible on an account, you should try testing combinations of actions where there is a possibility of failure (if any).

You'd save yourself a lot of time if you used one of the common testing frameworks, such as JUnit (http://www.junit.org/).

More than the act of testing, the act of designing tests is one of the best bug preventers known. The thinking that must be done to create a useful test can discover and eliminate bugs before they are coded - indeed, test-design thinking can discover and eliminate bugs at every stage in the creation of software, from conception to specification, to design, coding and the rest...
B. Bezier

Londbrok
May 6th, 2008, 10:31 AM
Starting with testing and a proper testing framework is good business. Dlorde mentioned JUnit, which is a good enough choice, especially as it is a build in feature in most of the IDE´s I have used.

Testing also encourages testability. Looking at the code you posted, you seem to have those angles covered quite well. Tests aim to verify that action that can be performed yield expected results, and that changes to the state of the application do not get suprising. Clearly then, writing methods that change gazillion of instance variables, contain endless spiderweb of if -clauses and may return whatsoever, drain all joy out of the effort of testing. What cannot be tested, cannot be trusted.

Also thinking of testability, when designing your code, leads you to appreciate the possible dangers that lurk in inheritance and overridable methods and all the nasty things that might come about handing out Object variables. True that you cannot ever safe from all the harm, but testing helps you grasp what might go wrong, already when the application is just an idea.

gammaman
May 6th, 2008, 03:57 PM
Does this test application look any better than before?


public class AccountTest {

public static void main(String[] args){
Date aDate = new Date( 7, 24, 1949 );
Account account=new Account("Bob","Power",aDate,2000.0);
CheckingAccount cAccount=new CheckingAccount("John","Doe",aDate,5000.0,10.0);
SavingsAccount sAccount=new SavingsAccount("Sarah","Black",aDate,6000.0,0.05);
account.toString();
account.debit(1000);
account.toString();
account.credit(500);
System.out.format("Balance: %5.2f\n",account.getBalance());
account.setBalance(4000);
System.out.format("New Balance: %5.2f\n",account.getBalance());
System.out.format("Date: %10s\n",account.getDate());
account.toString();
System.out.printfln(cAccount.toString());
cAccount.debit(2000);
System.out.println(cAccount.toString());
cAccount.credit(200);
System.out.println(cAccount.toString());
System.out.println(sAccount.toString());
sAccount.debit(2000);
System.out.println(sAccount.toString());
sAccount.credit(200);
System.out.println(Account.toString());
System.out.format("Current interest: %5.2f\n",sAccount.calculateInterest());
}

}

Londbrok
May 6th, 2008, 04:51 PM
Something stopping you from actually trying out a JUnit testcase? Sure, testing this way is better than not testing at all, but the fact remains, that the actual test does not happen, simply by calling a method. There is no validation, so in this way you would have to be the validator yourself, and as humans remain humane, that is simply not a very fail proof test approach.

Time you spend on honing your test mains, you could spend on learning the actual thing. Especially as the app you have is very good testing learning material. The concept of JUnit testing is fairly straight forward, very well covered in material, examples and tutorials. And well worth getting to know.

keang
May 6th, 2008, 05:03 PM
Did you bother to compile and run this test class to check that it output the expected values?

The reason I ask is that printfln(..) is not a valid method name for the System.out object so your code doesn't compile and the repeated calls to account.toString() don't do anything useful as you are ignoring the returned formatted string ie you are not printing the returned value to the console.

Just changing the values and printing the new values to the screen is not a very good test as it relies on someone to visually check that the value is correct. If you aren't going to do as others have suggested and use JUnit tests then at the very least get the test program to compare the actual and expected values and print a message giving the test details and a Passed/Failed message depending on the result.

dlorde
May 6th, 2008, 05:30 PM
But that code isn't really testing anything, it's just printing out values. You may be happy to rely on the toString() methods and visual comparison, but code that uses your classes isn't going to use toString() methods to get values out of them, nor is it likely that you'll want to manually compare all the printed values every time you test the class (i.e. every time any change is made). It's far better to have a boolean true/false answer to the question 'Does this method (still) work as expected?', something like this://pseudocode
boolean testSomeMethod() {
SomeClass someClass = new SomeClass(); // class under test
expectedOutputValue = <OUTPUT_VALUE>;
inputValue = <someValue>;
outputValue = someClass.someMethod(inputValue); // call method under test
return outputValue equals expectedOutputValue;
}This kind of structure allows you to automate the testing - if any test method returns 'false', you know you have a problem. Testing frameworks like JUnit make it simpler to do this, allow you to supply appropriate error messages to identify problems, and let you run a whole bunch of tests and display the results automatically.

Learning how to write tests and use a testing framework is a small up front investment in time that will save you far more in the long term, and is probably the best way to ensure you continue to write tests for your code, which is probably the best way to ensure your code is reliable...

The tools we use have a profound (and devious!) influence on our thinking habits, and, therefore, on our thinking abilities...
E. Dijkstra

dlorde
May 6th, 2008, 05:35 PM
Oops - I see Keang got there first ;-) That'll teach me to leave things halfway through to watch TV... :rolleyes:

Luckily, our advice seems to be fairly complementary :thumb:

JUnit: Never in the field of program testing, was so much owed by so many to so few lines of code...
M. Fowler