Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
with JUnit
Alessandro Marchetto
Fondazione Bruno Kessler - IRST
Iterative Software development
Write
and
execute
unit tests Execute
Write
acceptance
acceptance
tests
tests
increment
+ system
HttpUnit/Canoo/Selenium
Persistence Junit/SQLUnit/XMLUnit
Layer
3
Testing with JUnit
4
Junit (3.x and 4.x)
Test framework
test cases are Java code
test case = “sequence of operations +inputs + expected
values”
Test code
Production code
testDoubleOf2(){
int doubleOf2(){ //… //..
} doubleOf2();
//..
}
5
JUnit 3.x for testing programs
JUnit tests
“substitute the use of main() to check the program
behaviour”
All we need to do is:
junit.framework.*
write a sub-class of TestCase
add to it one or more test methods
run the test using JUnit
6
Framework elements
TestCase
Base class for classes that contain tests
assert*()
Method family to check conditions
TestSuite
Enables grouping several test cases
Testcase 1
Testsuite Testcase 2
Testcase 3
7
class Stack {
public boolean isEmpty(){ ... }
An example public void push(int i){ ... }
public int pop(){ ... }
…
}
import junit.framework.TestCase;
public class StackTester extends TestCase {
public StackTester(String name) {
super(name);
}
public void testStack() { Must begin with
Stack aStack = new Stack(); “test”
if(!aStack.isEmpty()) {
System.out.println(“Stack should be empty!”);
aStack.push(10);
aStack.push(-4);
System.out.println(“Last element:“ + aStack.pop());
System.out.println(“First element: “ +aStack.pop());
}
}
8
Method family to check conditions …
Assert*()
They are public methods defined in the base class
TestCase
Their names begin with “assert” and are used in test
methods
es. assertTrue(“stack should be empty”, aStack.empty());
If the condition is false:
test fails
execution skips the rest of the test method
the message (if any) is printed
If the condition is true:
execution continues normally
9
Assert*()
for a boolean condition
assertTrue(“message for fail”, condition);
assertFalse(“message”, condition);
for object, int, long, and byte values obtained
assertEquals(expected_value, expression);
for float and double values
assertEquals(expected, expression, error);
for objects references
assertNull(reference)
assertNotNull(reference)
…
10
http://junit.org/apidocs/org/junit/Assert.html
Assert: example
class Stack {
public boolean isEmpty(){ ... }
public void push(int i){ ... }
public int pop(){ ... }
…
}
11
Code Modularization …
One concept at a time …
12
Working rule
13
TestSuite
junit.framework.*
Groups several test cases:
14
Test of “Exceptions”
15
We expect a normal behavior …
try {
// We call the method with correct parameters
object.method("Parameter");
assertTrue(true); // OK
} catch(PossibleException e){
fail(“method should not fail !!!");
}
class TheClass {
public void method(String p)
throws PossibleException
{ /*... */ }
}
16
We expect an exception …
try {
// we call the method with wrong parameters
object.method(null);
fail(“method should fail!!");
} catch(PossibleException e){
assertTrue(true); // OK
} class TheClass {
public void method(String p)
throws PossibleException
{ /*... */ }
}
17
SetUp() and tearDown()
ShoppingCart cart;
Book book;
protected void setUp() {
cart = new ShoppingCart();
book = new Book(“JUnit", 29.95);
cart.addItem(book);
}
…
18
Junit in eclipse - Setup
In Eclipse
Create a new project
Open project’s property
window (File ->
Properties)
Select: Java build path
Select: libraries
Add Library
Select Junit
Select the type 3.x or 4.x
19
Create a new JUnit test case
Eclipse Menu
File Edit Source Refactor Navigate Search Project Run Window Help
File
New
Junit Test Case
20
Run as JUnit Test
Eclipse Menu
File Edit Source Refactor Navigate Search Project Run Window Help
Run
Run As
Junit Test
21
Red / Green Bar
Fail
Pass
22
JUnit 3.x and JUnit 4.x
Most things are about equally easy
JUnit 4 can still run JUnit 3 tests
All the old assertXXX methods are the same
JUnit 4 has some additional features
JUnit 4 provides protection against infinite loops
Junit 4 uses annotations (@)
23
From JUnit 3.x to 4.x
JUnit 4 requires Java 5 or newer
Don’t extend junit.framework.TestCase; just use an
ordinary class
Import org.junit.* and org.junit.Assert.*
Use a static import for org.junit.Assert.*
Static imports replace inheritance from
junit.framework.TestCase
Use annotations instead of special method names:
Instead of a setUp method, put @Before before some method
Instead of a tearDown method, put @After before some method
Instead of beginning test method names with ‘test’, put @Test
before each test method
24
Annotations in J2SE
http://java.sun.com/docs/books/tutorial/java/javaOO/annotations.html
25
Annotations in J2SE … an example
…. @Override — it is a predefined annotation used by
the Java compiler
It informs the compiler that the element (a method) is meant
to override an element declared in a superclass
27
Junit 4.x for testing programs (2)
If needed, define one method to be executed just once,
when the class is first loaded. For instance, when we
need to connecting to a database
@BeforeClass
public static void setUpClass() throws Exception {
// one-time initialization code
}
28
Junit 4.x for testing programs (3)
If needed, define one or more methods to be executed before
each test, e.g., typically for initializing values
@Before
public void setUp() {
program = new MyProgram();
array = new int[] { 1, 2, 3, 4, 5 };
}
29
@Before and @After methods
More than one @Before and/or @After methods can be
defined in a test case
Attention: we don’t know in what order they will execute
We can inherit @Before and @After methods from a
superclass; execution is as follows:
Execute the @Before methods in the superclass
Execute the @Before methods in this class
Execute a @Test method in this class
Execute the @After methods in this class
Execute the @After methods in the superclass
30
Junit 4.x for testing programs (4)
@Test
public void sum() {
assertEquals(15, program.sum(array));
assertTrue(program.min(array) > 0);
}
31
Additional Features of @Test
To avoid infinite loops, an execution time limit can be used.
The time limit is specified in milliseconds. The test fails if
the method takes too long.
@Test (timeout=10)
public void greatBig() {
assertTrue(program.ackerman(5, 5) > 10e12);
}
32
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
Parameterized tests
Using @RunWith(value=Parameterized.class) and a method
@Parameters, a test class is executed with several inputs
@RunWith(value=Parameterized.class)
public class FactorialTest {
private long expected; Parameters used to exercise
private int value; different instances of the class
@Parameters
public static Collection data() {
return Arrays.asList( new Object[ ][ ] { { 1, 0 }, { 1, 1 }, { 2, 2 }, { 120, 5 } });
}
@Test
public void factorial() {
assertEquals(expected, new Calculator().factorial(value));
}
} 33
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
Test suites
34
Additional features of Junit 4
Instead of JUnit 3’s AssertionFailedError, now failed tests throw
an AssertionError
@Override
public boolean equals(Object o){
… return …;
}
35
Autoboxing example
Consider the following method:
“long sum(long x, long y) { return x + y; }”
and the following test:
@Test
public void sum() { assertEquals((long)4, s.sum(2, 2));
assertEquals(4, s.sum(2, 2));
}
it fails and gives:
expected: <4> but was: <4>
This is for the autoboxing
assertEquals no longer exists for primitives, only for objects!
Hence, the 4 is autoboxed to an Integer, while sum returns a long
The error message means: expected int 4, but got long 4
To make this work, change the 4 to a “4L” or “(long)4”
Note that this problem has been fixed starting form JUnit 4.4
36
Summarizing… an example (Junit 3.x)
Test case 1
public class Add {
public static int sum (int a, int b) {
return a+b;
}
}
import junit.framework.TestCase;
import math.Add;
37
Summarizing… an example (Junit 3.x)
Test case 2
import junit.framework.TestCase;
import math.Add;
38
Summarizing… an example (Junit 3.x)
Test case 2
import junit.framework.TestCase;
import math.Add;
39
Summarizing… an example (Junit 4.x)
public class Add {
public static int sum (int a, int b) {
return a+b;
}
}
import math.Add;
import org.junit.*;
import static org.junit.Assert.*;
@Test
public void testAdd() {
Add add=new Add();
int sum=add.sum(3, 2);
assertEquals(5, sum);
}
}
40
When testing programs?
Test last
The conventional way for testing in which testing
follows the implementation
Test first
The Extreme-Programming view in which testing is
used as a developement tool
41
Test last
Implement functionality
Write tests
fail
Rework Result? pass
Next functionality
42
“Extreme programming” (XP) champions the use of tests as a development tool …
Test first
fail No
Rework Result? pass
Functionality
Yes complete?
Next functionality
43
Test First Advantages
44
Test-first with Junit Add a testcase
Rework
Refactoring
“improving the structure”
Run test
Junit in practice …
Existing system: a class current account to
manage a bank account
deposit
withdraw
Add a new functionality
settlement
Example:
CurrentAccount cc = new CurrentAccount();
cc.deposit(12);
cc.draw(-8);
cc.deposit(10);
cc.settlement()
expected value 14 euro!
46
Add a testcase
47
Add Testcases for the settlement method
49
Add the skeletone code of
class CurrentAccount {
int account[];
the method
int lastMove;
51
Run Junit (first time)
Rework
53
class CurrentAccount { Rework
int account[];
int lastMove;
55
Run Junit (second time)
Add a testcase
57
class CurrentAccount { Add a new testcase
int account[];
int lastMove;
59
Run JUnit (third time) Run time error
Rework
61
class CurrentAccount {
int account[];
Rework
int lastMove;
63
Run JUnit (fourth time)
Refactoring
“improving the structure”
65
public class CurrentAccount {
List account = new LinkedList();
Refactoring
public void deposit(int value) {
account.add(new Integer(value));
}
67
Run JUnit (fifth time)
The End
69
xUnit
2.1 ActionScript 2.21 Perl
Junit: it is one of many in 2.2 Ada 2.22 PHP
the xUnit family…. 2.3 BPEL
2.4 C
2.23 PL/SQL
2.24 PowerBuilder
NUnit 2.5 C++ 2.25 Prolog
2.6 ColdFusion (CFML) 2.26 Python
It is an open source unit 2.7 Delphi 2.27 REALbasic
testing framework for 2.8 Emacs Lisp
2.9 Fortran
2.28 Ruby
2.29 SAS
Microsoft .NET. 2.10 Haskell 2.30 Scala
2.11 Internet 2.31 Shell
It serves the same 2.12 Java 2.32 Simulink
purpose as JUnit does 2.13 JavaScript 2.33 Smalltalk
70
“The tip of the iceberg”
Coverage testing (JCoverage, Clover,
…)
Integration testing
System/GUI testing (Jemmy, Abbot,
…)
Testing legacy applications
Testing J2EE applications
Testing database applications.
Testing EJBs
Testing Web applications (HttpUnit,
JWebUnit, …)
Testing Web services
Testing in isolation with Mock Objects
…
71
References
72