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>