Wednesday, November 24, 2010

JUnit

JUnit is a regression-testing framework that developers can use to write unit tests as they develop systems.
JUnit provides also a graphical user interface (GUI) which makes it possible to write and test source code quickly and easily.

public class Calculator{
int sum(int num1,int num2){
return num1+num2;
}
}

Coding Convention :
1. Name of the test class must end with "Test".
2. Name of the method must begin with "test".
3. Return type of a test method must be void.
4. Test method must not throw any exception.
5. Test method must not have any parameter.

import junit.framework.TestCase;

public class CalculatorTest extends TestCase { //each of our testing class should extend TestCase class
Calculator cal=new Calculator();

public CalculatorTest(String name) { //every test is given name. The constructor of the class provides this functionality by passing this parameter to the constructor of the parent class
super(name);
}

public void testSum() {
assertEquals(2,cal.sum(1,1));
}
}

If the method did not perform as expected then it will cause assertEquals() to fail.
Now we need to fix the problem and run the test again .
We need to repeat this process until the test is passed.

How to run JUnit in text mode :

Execute > java junit.textui.TestRunner CalculatorTest.
The passing test results in the following textual output:

Time: 0
OK (1 test)


public class TestRunner
extends BaseTestRunner
A command line based tool to run tests.
java junit.textui.TestRunner [-wait] TestCaseClass

TestRunner expects the name of a TestCase class as argument. If this class defines a static suite method it will be invoked and the returned test is run. Otherwise all the methods starting with "test" having no arguments are run.
When the wait command line argument is given TestRunner waits until the users types RETURN.
TestRunner prints a trace as the tests are executed followed by a summary at the end.
======================================================================================================================

public class Subscription {

public int price; // subscription total price in euro-cent
public int length; // length of subscription in months

/**
* A constructor to create a subsription.
*/
public Subscription(int p, int n) {
price = p;
length = n;
}

/**
* Calculate the monthly subscription price in euro, rounded up to the
* nearest cent.
*/
public double pricePerMonth() {
if (length <= 0 || price <= 0) return 0; double r = (double) price / (double) length; double fraction = Math.IEEEremainder(r, 1.0); if (fraction > 0)
return Math.floor(r) + 1;
else
return Math.floor(r);
}

/**
* Call this to cancel/nulify this subscription.
*/
public void cancel() {
length = 0;
}
}

TEST CASES:
package test;

import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class SubscriptionTest {

Subscription s1;
Subscription s2;

@Before
public void setUp() throws Exception { //Called everytime before a testCase function is executed. Life-Cycle method
s1 = new Subscription(100, 2);
s2 = new Subscription(200, 3);
}

@After
public void tearDown() throws Exception { //Called everytime after a testCase function is executed. Life-Cycle method
s1 = null;
s2 = null;
}

@Test
public void testPricePerMonth() {
assertTrue(s1.pricePerMonth() == 50);
assertTrue(s2.pricePerMonth() == 66.0);
}

@Test
public void testCancel() {
s1.cancel();
assertTrue(s1.length == 0);
assertFalse(s2.length == 0);
}

}

prompt> javac -cp .; SubscriptionTest.java
prompt> java -cp .; org.junit.runner.JUnitCore SubscriptionTest

Time: 0,015

There were 2 failures:

1) test_returnsEuro(SubscriptionTest)
java.lang.AssertionError:
...
at SubscriptionTest.test_returns_Euro(SubscriptionTest.java:13)
...

2) test_roundUp(SubscriptionTest)
...
at SubscriptionTest.test_roundUp(SubscriptionTest.java:19)
...

Tests run: 2, Failures: 2

We keep fixing it until we get no more failures.


TestSuite

If you have two tests and you'll run them together you could run the tests one at a time yourself, but you would quickly grow tired of that. Instead, JUnit provides an object TestSuite which runs any number of test cases together. The suite method is like a main method that is specialized to run tests.

Create a suite and add each test case you want to execute:

public static void suite(){
TestSuite suite = new TestSuite();
suite.addTest(new BookTest("testEquals"));
suite.addTest(new BookTest("testBookAdd"));
return suite;
}


Since JUnit 2.0 there is an even simpler way to create a test suite, which holds all testXXX() methods. You only pass the class with the tests to a TestSuite and it extracts the test methods automatically.

Note: If you use this way to create a TestSuite all test methods will be added. If you do not want all test methods in the TestSuite use the normal way to create it.

Example:

public static void suite(){
return new TestSuite(BookTest.class);
}


Run JUNIT using Ant
< target name="test">
<junit fork="yes" printsummary="no" haltonfailure="no">
<test name="${test.class.name}" />
<formatter type="plain" usefile="false" />
<classpath refid="test.classpath" />
</junit>
</target>


ant test

#

Define the Ant task for running JUnit and generating reports:

<target name="test-html">
<junit fork="yes" printsummary="no" haltonfailure="no">
<batchtest fork="yes" todir="${test.reports}" >
<fileset dir="${classes}">
<include name="**/*Test.class" />
</fileset>
</batchtest>
<formatter type="xml" />
<classpath refid="test.classpath" />
</junit>

<junitreport todir="${test.reports}">
<fileset dir="${test.reports}">
<include name="TEST-*.xml" />
</fileset>
<report todir="${test.reports}" />
</junitreport>
</target>

JDBC

import java.sql.*;
Load Driver Class
Class.forName("jdbc-driver"); //initializes static block d/b variables initialized
4 types of Drivers:
type 1: ODBC Bridge
type 2 & 3: Needs client s/w to be installed at client d/b
type 4: Direct recommended by Sun
type 2 ---- developed in Native Code
type 3 & 4 ---- developed in java
Connection con = DriverManager.getConnection("jdbc:myDriver:d/bSource", "Login","Password");
The Standard Extension packages javax.naming and javax.sql let you use a DataSource object registered with a Java Naming and Directory Interface™ (JNDI) naming service to establish a connection with a data source. An application to use a logical name for a data source instead of having to supply information specific to a particular driver. (preferred)
InitialContext ic = new InitialContext();
DataSource ds = ic.lookup("java:comp/env/jdbc/myDB");
ds.setPort(1527); ds.setHost("localhost"); ds.setUser("APP"); ds.setPassword("APP");
Connection con = ds.getConnection();

a DataSource can usually be configured and managed by the application server instead of your application. It means that the connections you get from a DataSource can come from a connection pool for performance. It means that the connections may participate in a container-managed distributed transaction without you having to worry about the nitty gritty of it.
------------------------------------------------------------------------------------
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1");
while (rs.next()) { sop ( rs.getInt("a") + rs.getString("b") + rs.getFloat("c"));
con.close(); //finally block
To update d/b Table
int count = st.executeUpdate("insert int Table1 values (123, b, 123.111)"); //returns rows updated in d/b

Using Prepared Statement -- each time sql statement compilation is not required
PreparedStatement pstmt = con.prepareStatement("insert into Table1 values(?, ?, ?)");
pst.setInt(1,123); pst.setString(2, "xxx"); pst.setFloat(3, 123.111);
int count = pst.executeUpdate();
pst.setInt(1,456); pst.setString(2, "yyy");
int count = pst.executeUpdate();

---------------------------Meta Data------------------------------
ResultSetMetaData metaData = rset.getMetaData();
int count = metaData.getColumnCount();
for( int i=1; i<=count; i++)
{ sop ( metaData.getColumnLabel(i) + metaData.getColumnTypeName(i) + metaData.getColumnTypeSize(i) );

-------------------Commit and Rollback--------------------------
con.setAutoCommit(false); //true by default
con.rollback;
con.commit();

--------------------execute Batch (reduces d/b hits)--------------
PreparedStatement pstmt = con.prepareStatement("insert into Table1 values(?, ?, ?)");
pst.setInt(1,123); pst.setString(2, "xxx"); pst.setFloat(3, 123.111);
pst.addBatch();
pst.setInt(1,456); pst.setString(2, "yyy"); pst.setFloat(3, 123.111);
pst.addBatch();
pst.executeBatch(); //only one d/b hit

----------------Callable Stmt--------------------------------------
Used for d/b stored procedures and functions execution
CallableStatement cs = con.prepareCall("{call SHOW_SUPPLIERS}");
ResultSet rs = cs.executeQuery();

DAO - data access object (encapsulates all d/b related functionalities)