Nikon D5000 | DVD rental | Debt Help | Cheap Home Insurance | Find jobs
need help designing junit tests for a time-dependent class [Archive] - Muslim Programmers & Designers Community - Islamic Webhosting and Nasheeds

PDA

View Full Version : need help designing junit tests for a time-dependent class



abdullah
11-01-2004, 02:37 PM
assalamu 'alaikum,

i wrote a class which is supposed to be run as a thread in the main application. what it does is basically calculate the time when it needs to wake up and play an audio file. it does this, based on system time.

i have no idea of how i can write a junit test (to test this class, even if it was run as the main class.. or is that a bad idea?) ... if anyone can point me in the right direction that will be great.

the other alternative is to monitor it for 2 days, get the bugs, and rectify.. and wait for another 2 days..but that will take a very long time.. and i want to get this done as soon as possible.


just in case my question is not clear, i have attached the source code for the whole class. i would paste the code here, but the file is 230 lines.

if anyone can help me with the algorithm, that will be great too.

thanks in advance..

EDIT:

i thought i would post the run() method here..if any1 doesnt want to view the attachment




public void run() {
java.util.Date date = new java.util.Date();

//if times stored are not for today, then update them
if (sdate.getDate() != date.getDate() || sdate.getMonth() != date.getMonth() || sdate.getYear() != date.getYear()) {
updatePrayerTimes(date);
}

int ph,pm,ps;

//need an algorithm for this...
if (time == -1) {
int dh = date.getHours();
int dm = date.getMinutes();
int ds = date.getSeconds();
int j = -1;

for (int i=0; i<6; i++) {
if (i == 0)
j = 5;
else
j = i-1;

if (i == 1)
continue;
if (i == 2) {
if (ptlist[2].getHour() > ptlist[3].getHour()) { //this means dhur starts in pm
if (ptlist[2].getHour() == 12)
ph = 12;
else
ph = 12 + ptlist[2].getHour();
} else {
ph = ptlist[2].getHour();
}
pm = ptlist[2].getHour();
} else {
ph = ptlist[i].getHour();
pm = ptlist[i].getMinute();
}

if (dh < ph) {
time = j;
break;
}
if (dh == ph && dm < pm) {
time = j;
break;
}

if (dh == ph && dm == pm && ds < ptlist[0].getSecond()) {
time = j;
break;
}

/*
if (dh < ph)
time = i;
if (dh == ph && dm < pm)
time = i;
if (dh == ph && dm == pm && ds < ptlist[0].getSecond())
time = i;
*/
}
}

System.out.println("TIME OUT OF FOR: "+time+"");
while (true) {
int j, tot;
java.util.Date d2 = new java.util.Date();

if (time == 5)
j = 0;
else
j = time+1;

System.out.println("TIME IN WHILE: "+time+"");
System.out.println("J IN WHILE: "+j+"");
//get the time difference between now and the time for next prayer
if (time == 5) { //then fajr will be next day

int month = date.getMonth();
int d = date.getDate();

if (month == 2) { //TODO: correct the algorithm for leap years
tot = 28;
} else if ((month % 2) == 0) {
tot = 31;
} else {
tot = 30;
}

if (date.getDate() == tot) {
d2.setMonth(month+1);
d2.setDate(1);
} else {
d2.setDate(d+1);
}

}

updatePrayerTimes(d2);

System.out.println("D2 :"+d2.toString());
d2.setHours(ptlist[j].getHour());
d2.setMinutes(ptlist[j].getMinute());
d2.setSeconds(ptlist[j].getSecond());


long diff = d2.getTime() - date.getTime();

//now that we have time difference, we play the adhan and we sleep
playAdhan();
try {
Thread.sleep(diff + 1000); //sleep for 1 second more than required, to be safe
} catch (Exception e) {
System.out.println(e.toString());
}
time = j;


}
}

Eyyub
11-02-2004, 02:58 PM
I dont have time to look at your whole code, but JUnit is very easy.
It is in fact blackbox testing. Here are some guidelines to set up your own
testcases in JUnIt:

First you need to know what cases you want test. I dont know what that
class of you really does, but let's say you have the prayer times, and when
it is time you will hear the adhaan.

Then you have to find inputs and execute them and compare the results
of it with the expected results.

OK, here is the structure of how you should define a testcase for your
JPAudio class:



import junit.framework.TestCase;
import junit.framework.Assert;

public class JPAudioTest extends TestCase
{
private JPAudio audio;

public JPAudioTest(String arg)
{
super(arg);
}

public void setUp()
{
audio = new JPAudio();
}

/* Here you test the correct working of your adhaan
* by setting some inputs and comparin them with what you expect
*/
public void testAdhaan()
{
// test fadr, by setting time on 05:30;
// assuming there is a method called setCurrentTime in JPAudio
// the adhaan should go on now;
// assuming that there is a method called playAdhaan()
// which returns a boolean (true=adhaan is played,
// otherwise false)
audio.setCurrenttime("new Date("15-11-2004t0530"));
Assert.assertTrue(audio.playAdhaan());

// test fadjr, by setting time on 05:00
// the adhaan should not be played now
audio.setCurrenttime(new Date("15-11-2004t0500"));
Assert.assertFalse(audio.playAdhaan());

// and so on...test all the other cases
// by providing inputs and comparing them with what you expect
}
}


you can run this testcase on you command prompt on this way:
java junit.swingui.TestRunner <your testclass>

But you need to download junit.jar fisrt and set it on your classpath.
This maybe what hard to do. The easiest way is to make use of tools
like Eclipse, NetBeans, etc. Because they have already JUNit and
you can run it very easily by just pressing a button or something like that.

After you have run your testcase a green or red light will show up.
Red means that there is something wrong with your implementation of your
JPAudio class (the linenumbers will be shown) and you have to correct them
till you get a green light.

That's the whole idea.

One important thing is that all the testcases you write must have this
signature:


public void testSomeName()

Otherwise you will get an error.

Note that the testcase name I had used in my example was testAdhaan(),
in which I test all the possiblities. What you also can do is split the testAdhaan()
method in different testcases like: testFadr(), testZohr(), testAsr(), etc.
Just do what you prefer.

Eyyub
11-02-2004, 03:12 PM
Here are some examples of mine, just to illustrate you the idea about JUnit.



package example.connectionpool.test;


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import junit.framework.TestCase;
import junit.framework.Assert;

import example.connectionpool.ConnectionPool;
import example.connectionpool.ConnectionPoolFactory;



/**
* @author Eyyub
*/
public class ConnectionPoolTest extends TestCase
{
private static final String DB = "f:\\temp\\FilmDB.mdb";
private ConnectionPool cp;
private String url;


/**
* Constructor for TestConnectionPool.
*
* @param arg0
*/
public ConnectionPoolTest(final String arg0)
{
super(arg0);
}


/* (non-Javadoc)
* @see junit.framework.TestCase#setUp()
*/
protected void setUp() throws Exception
{
super.setUp();
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
url = "jdbc:odbc:Driver="
+ "{Microsoft Access Driver (*.mdb)};DBQ="
+ DB.trim();
cp = ConnectionPoolFactory.createInstance(4, url);
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
}
}


/* (non-Javadoc)
* @see junit.framework.TestCase#tearDown()
*/
protected void tearDown() throws Exception
{
super.tearDown();
cp.closeAll();
}


/*
* Twice instantiation test. This should not be possible.
*/
public void testCreateInstance1()
{
try
{
ConnectionPool cp1 =
ConnectionPoolFactory.createInstance(10, url);

Assert.fail("This should fail");
}
catch(IllegalArgumentException e)
{
e.printStackTrace();
}
catch(IllegalAccessException e)
{
e.printStackTrace();
}
}


/*
* Tests 2nd instantiation of the pool, by closing the first pool
* and creating a second (new) one.
*
* This should be possible.
*/
public void testCreateInstance2()
{
cp.closeAll();
try
{
ConnectionPool cp1 =
ConnectionPoolFactory.createInstance(3, url);

Assert.assertEquals(cp.size(), 0);
Assert.assertEquals(cp1.size(), 3);

Connection c1 = cp1.getConnection();
Connection c2 = cp1.getConnection();
Connection c3 = cp1.getConnection();
Connection c4 = cp1.getConnection();

Assert.assertEquals(cp1.size(), 6);
Assert.assertTrue(c1.hashCode() != c2.hashCode());
Assert.assertTrue(c2.hashCode() != c3.hashCode());
Assert.assertTrue(c3.hashCode() != c4.hashCode());

cp1.closeAll();
}
catch(IllegalArgumentException e)
{
e.printStackTrace();
}
catch(IllegalAccessException e)
{
e.printStackTrace();
}
}


/*
* Tests getConnection and returnConnection from ConnectionPool
*
* -Test1: creates 4 connections -> the size of the pool must be 4;
* -Also all the 4 connections must not be equal to each other.
* -Test2: creates a new Connection (c5), the size must be 8 now and
* its hashcode must also not be equal to the previous
* connections.
* -Test3: returns c5 back to the pool:
* -size must be still 8 and...
* -Test4: when another Connection c6 is created, its hashcode
* must be equal to c5's hashcode.
* -Test5: if a Connection is returned to the pool which doesn't
* belong there, then returnConnection() must return false.
*/
public void testGetReturnConnection()
{
//Test1
Connection c1 = cp.getConnection();
Connection c2 = cp.getConnection();
Connection c3 = cp.getConnection();
Connection c4 = cp.getConnection();

Assert.assertEquals(cp.size(), 4);
Assert.assertTrue(c1.hashCode() != c2.hashCode());
Assert.assertTrue(c2.hashCode() != c3.hashCode());
Assert.assertTrue(c3.hashCode() != c4.hashCode());

//Test2
Connection c5 = cp.getConnection();
Assert.assertEquals(cp.size(), 8);
Assert.assertTrue(c5.hashCode() != c4.hashCode());

//Test3
cp.returnConnection(c4);
cp.returnConnection(c5);
cp.returnConnection(c3);
Assert.assertEquals(cp.size(), 8);

//Test4
Connection c6 = cp.getConnection();
Connection c8 = cp.getConnection();
Connection c9 = cp.getConnection();
Assert.assertEquals(c5.hashCode(), c6.hashCode());

//Test5
Assert.assertFalse(cp.returnConnection(null));

try
{
Connection c7 = DriverManager.getConnection(url);
Assert.assertFalse(cp.returnConnection(c7));
c7.close();
}
catch(SQLException e)
{
e.printStackTrace();
}
}


/*
* Tests whether no any method call to ConnectionPool
* can be done after closeAll() is called.
*/
public void testCloseAll()
{
Connection cp1 = cp.getConnection();
cp.closeAll();

try
{
cp.getConnection();
Assert.fail("This should fail");

Assert.assertFalse(cp.returnConnection(cp1));
cp1.close();

Assert.assertTrue(cp.size() == 0);
}
catch(Exception e)
{
Assert.assertTrue(e instanceof IllegalStateException);
}
}
}





package pacman.model;


import junit.framework.TestCase;


public class BoardTest extends TestCase
{
int width;
int height;
Board theBoard;


/**
* @param name
*/
public BoardTest(String name)
{
super(name);
}


public void setUp()
{
width = 5;
height = 10;
theBoard = new Board(5, 10);
}


public void testwithinBorders()
{
assertTrue(theBoard.withinBorders(0, 1));
assertTrue(theBoard.withinBorders(1, 2));
assertTrue(theBoard.withinBorders(2, 0));
assertTrue(theBoard.withinBorders(5, 19));
assertFalse(theBoard.withinBorders(20, 3));
assertFalse(theBoard.withinBorders(21, 4));
assertFalse(theBoard.withinBorders(3, -1));
assertFalse(theBoard.withinBorders(4, 20));
}
}

abdullah
11-03-2004, 02:54 AM
thanks for the reply bro

Eyyub
11-03-2004, 10:17 AM
OK, one thing what I maybe didn't make clear is, that you write testcases about
the (public) methods in your class. So let's say that you have the following methods
in your JPAudio class:

-setCurrentTime(...)
-getFadjrTime(...)
-playAdhaan(...)


Then you have to provide these testcases in your JPAudioTest class:

-testSetCurrentTime() --> tests whether setCurrenTime(...) works correctly.
-testGetFadjrTime() --> " " " getFadjrTime(...) " " .
-testPlayAdhaan() --> " " " playAdhaan(...) " " .


Also the order of the testcases is important, that is: if you use the method
setCurrentTime(...) in testPlayAdhaan(), than you should test that first, then
test playAdhaan(...). Maybe setCurrentTime(...) contains bugs and then the test
for playAdhaan(...) will also fail, while the implementation of playAdhaan(...)
was correct. So to exclude confusions it is better to the test all the elementary
methods first, then the complicated ones.

In this case the order of the testcases should be like this:



public class JPAudio extends TestCase
{
JPAudio audio;

public JPAudio(String arg)
{
super(arg);
}

public void testSetCurrentTime() {}
public void testGetFadjrTime() {}
public void testPlayAdhaan() {}
}