JUnit Testing Framework JUnit Testing Framework

utopianthreeΛογισμικό & κατασκευή λογ/κού

14 Ιουλ 2012 (πριν από 5 χρόνια και 3 μήνες)

354 εμφανίσεις

1


JUnit Testing Framework
JUnit Testing Framework


Topics

What is and Why JUnit framework?
What is and Why JUnit framework?

JUnit mechanics
JUnit mechanics

Fixtures
Fixtures

Test suites
Test suites

Test runners
Test runners

JUnit classes
JUnit classes

Best practice guidelines
Best practice guidelines

Design patterns for testing
Design patterns for testing

Extensions
Extensions
3


Test-Driven Development
Test-Driven Development
(TDD)
(TDD)


Acknowledgment

This presentation is a modified (and
This presentation is a modified (and
enhanced) version of Orlando Java User's
enhanced) version of Orlando Java User's
Group presentation on the same subject
Group presentation on the same subject
by
by
Matt Weber




Why test?

Automated tests prove features
Automated tests prove features

Tests retain their value over time and
Tests retain their value over time and
allows others to prove the software still
allows others to prove the software still
works (as tested).
works (as tested).

Confidence, quality, sleep
Confidence, quality, sleep

Get to code sooner by writing tests.
Get to code sooner by writing tests.


Test-Driven Development (TDD)

Is a software development technique
Is a software development technique
that involves repeatedly first writing a
that involves repeatedly first writing a
test case and then implementing only the
test case and then implementing only the
code necessary to pass the test
code necessary to pass the test

Gives rapid feedback
Gives rapid feedback


Unit Testing

Is a procedure used to validate that
Is a procedure used to validate that
individual units of source code are
individual units of source code are
working properly
working properly

A unit is the smallest testable part of an
A unit is the smallest testable part of an
application
application

In procedural programming a unit may be an
In procedural programming a unit may be an
individual program, function, procedure, web
individual program, function, procedure, web
page, menu etc, while in object-oriented
page, menu etc, while in object-oriented
programming, the smallest unit is always a
programming, the smallest unit is always a
Class; which may be a base/super class,
Class; which may be a base/super class,
abstract class or derived/child class
abstract class or derived/child class
8


What is and Why
What is and Why
JUnit Testing Framework?
JUnit Testing Framework?


What is JUnit?

JUnit is a regression testing framework
JUnit is a regression testing framework

Used by developers to implement unit
Used by developers to implement unit
tests in Java (de-facto standard)
tests in Java (de-facto standard)

Integrated with Ant
Integrated with Ant

Testing is performed as part of nightly build
Testing is performed as part of nightly build
process
process

Goal: Accelerate programming and
Goal: Accelerate programming and
increase the quality of code.
increase the quality of code.

Part of XUnit family (HTTPUnit, Cactus),
Part of XUnit family (HTTPUnit, Cactus),
CppUnit
CppUnit


Why JUnit?

Without JUnit, you will have to use
Without JUnit, you will have to use
println() to print out some result
println() to print out some result

No explicit concept of test passing or failure
No explicit concept of test passing or failure

No mechanism to collect results in a
No mechanism to collect results in a
structured fashion
structured fashion

No replicability
No replicability

JUnit addresses all these issues
JUnit addresses all these issues


Key Goals of JUnit

Easy to use to create tests
Easy to use to create tests

Create tests that retain their value over time
Create tests that retain their value over time

Leverage existing tests to write new ones
Leverage existing tests to write new ones
(reusable)
(reusable)


What does JUnit provide?

API for easily creating Java test cases
API for easily creating Java test cases

Comprehensive assertion facilities
Comprehensive assertion facilities

verify
verify
expected versus actual results
expected versus actual results

Test runners for running tests
Test runners for running tests

Aggregation facility (test suites)
Aggregation facility (test suites)

Reporting
Reporting
13


How to Write JUnit
How to Write JUnit
Testing Code?
Testing Code?


How to write JUnit-based
testing code (Minimum)

Include JUnit.jar in the classpath
Include JUnit.jar in the classpath

Define a subclass of
Define a subclass of
TestCase
TestCase
class
class

Define one or more public
Define one or more public
testXXX()
testXXX()
methods in the subclass
methods in the subclass

Write assert methods inside the testXXX
Write assert methods inside the testXXX
methods()
methods()

Optionally define
Optionally define
main()
main()
to
to


run the
run the
TestCase in standalone mode
TestCase in standalone mode



Test methods

Test methods has name pattern
Test methods has name pattern
testXXX()
testXXX()

XXX reflects the method of the target class
XXX reflects the method of the target class

Test methods must have no arguments
Test methods must have no arguments

Test methods are type of void
Test methods are type of void


Example 1: Very Simple Test
import junit.framework.TestCase;
import junit.framework.TestCase;
public class SimpleTest extends TestCase {
public class SimpleTest extends TestCase {




public SimpleTest(String name) {
public SimpleTest(String name) {


super(name);
super(name);


}
}


// Test code
// Test code


public void testSomething() {
public void testSomething() {


System.out.println("About to call assertTrue() method...");
System.out.println("About to call assertTrue() method...");


assertTrue(4 == (2 * 2));
assertTrue(4 == (2 * 2));


}
}


// You don't have to have main() method, use Test runner
// You don't have to have main() method, use Test runner


public static void main(String[] args){
public static void main(String[] args){


junit.textui.TestRunner.run(SimpleTest.class);
junit.textui.TestRunner.run(SimpleTest.class);


}
}
}
}


How to write JUnit-based testing
code (More Sophisticated)

Optionally override the setUp() &
Optionally override the setUp() &
tearDown()methods
tearDown()methods

Create common test data
Create common test data

Optionally define a static suite()factory
Optionally define a static suite()factory
method
method



Create a TestSuite containing all the tests.
Create a TestSuite containing all the tests.


Example 2: More
Sophisticated Example
// Define a subclass of TestCase
// Define a subclass of TestCase
public class StringTest extends TestCase {
public class StringTest extends TestCase {




// Create fixtures
// Create fixtures


protected void setUp(){ /* run before */}
protected void setUp(){ /* run before */}
protected void tearDown(){ /* after */ }
protected void tearDown(){ /* after */ }
// Add testing methods
// Add testing methods


public void testSimpleAdd() {
public void testSimpleAdd() {


String s1 = new String(“abcd”);
String s1 = new String(“abcd”);


String s2 = new String(“abcd”);
String s2 = new String(“abcd”);


assertTrue(“Strings not equal”,
assertTrue(“Strings not equal”,


s1.equals(s2));
s1.equals(s2));


}
}


// Could run the test in batch mode
// Could run the test in batch mode
public static void main(String[] args){
public static void main(String[] args){


junit.textui.TestRunner.run (suite ());
junit.textui.TestRunner.run (suite ());
}
}


Example 2: Simple Testcase (cont.)
// Create TestSuite object
// Create TestSuite object
public static Test suite (){
public static Test suite (){


suite = new TestSuite (”StringTest");
suite = new TestSuite (”StringTest");


String tests = System.getProperty("tests");
String tests = System.getProperty("tests");


if (tests == null){
if (tests == null){


suite.addTest(new
suite.addTest(new


TestSuite(StringTest.class));
TestSuite(StringTest.class));


}else{
}else{


StringTokenizer tokens = new
StringTokenizer tokens = new


StringTokenizer(tests, ",");
StringTokenizer(tests, ",");


while (tokens.hasMoreTokens()){
while (tokens.hasMoreTokens()){


suite.addTest(new
suite.addTest(new


StringTest((String)tokens.nextToken()));
StringTest((String)tokens.nextToken()));


}
}


}
}


return suite;
return suite;
}
}
20


Assert
Assert
Statements
Statements


Assert statements

JUnit Assertions are methods starting with
JUnit Assertions are methods starting with
assert
assert

Determines the
Determines the
success or failure
success or failure


of a test
of a test

An
An


assert
assert


is simply a
is simply a
comparison
comparison
between
between
an
an
expected
expected
value and an
value and an
actual
actual
value
value

Two variants
Two variants

assertXXX(...)
assertXXX(...)

assertXXX(String message, ...) - the message is
assertXXX(String message, ...) - the message is
displayed when the assertXXX() fails
displayed when the assertXXX() fails


Assert statements

Asserts that a condition is true
Asserts that a condition is true

assertTrue(boolean condition)
assertTrue(boolean condition)

assertTrue(String message, boolean condition)
assertTrue(String message, boolean condition)

Asserts that a condition is false
Asserts that a condition is false

assertFalse(boolean condition)
assertFalse(boolean condition)

assertFalse(String message, boolean condition)
assertFalse(String message, boolean condition)


Assert statements

Asserts expected.equals(actual)
Asserts expected.equals(actual)


behavior
behavior

assertEquals(expected, actual)
assertEquals(expected, actual)

assertEquals(String message, expected, actual)
assertEquals(String message, expected, actual)

Asserts expected == actual
Asserts expected == actual


behavior
behavior

assertSame(Object expected, Object actual)
assertSame(Object expected, Object actual)

assertSame(String message, Object expected,
assertSame(String message, Object expected,
Object actual)
Object actual)


Assert statements

Asserts object reference is null
Asserts object reference is null

assertNull(Object obj)
assertNull(Object obj)

assertNull(String message, Object obj)
assertNull(String message, Object obj)

Asserts object reference is not null
Asserts object reference is not null

assertNotNull(Object obj)
assertNotNull(Object obj)

assertNotNull(String message, Object obj)
assertNotNull(String message, Object obj)

Forces a failure
Forces a failure

fail()
fail()

fail(String message)
fail(String message)
25


Fixtures
Fixtures


Fixtures

setUp() and tearDown() used to initialize
setUp() and tearDown() used to initialize
and release common test data
and release common test data

setUp() is run before every test invocation &
setUp() is run before every test invocation &
tearDown() is run after every test method
tearDown() is run after every test method


Example: setUp


public class MathTest extends TestCase {
public class MathTest extends TestCase {


protected double fValue1, fValue2;
protected double fValue1, fValue2;


protected void setUp() {
protected void setUp() {


fValue1= 2.0;
fValue1= 2.0;


fValue2= 3.0;
fValue2= 3.0;


}
}


public void testAdd() {
public void testAdd() {


double result= fValue1 + fValue2;
double result= fValue1 + fValue2;


assertTrue(result == 5.0);
assertTrue(result == 5.0);


}
}


public void testMultiply() {
public void testMultiply() {


double result= fValue1 * fValue2;
double result= fValue1 * fValue2;


assertTrue(result == 6.0);
assertTrue(result == 6.0);


}
}


}
}
28


Test Suites
Test Suites


Test Suites

Used to collect all the test cases
Used to collect all the test cases

Suites can contain testCases and testSuites
Suites can contain testCases and testSuites

TestSuite(java.lang.Class theClass,
TestSuite(java.lang.Class theClass,
<java.lang.String name>)
<java.lang.String name>)

addTest(Test test) or
addTest(Test test) or
addTestSuite(java.lang.Class testClass)
addTestSuite(java.lang.Class testClass)

Suites can have hierararchy
Suites can have hierararchy


Example: Test Suites
public static void main (String [] args){
public static void main (String [] args){


junit.textui.TestRunner.run (suite ());
junit.textui.TestRunner.run (suite ());
}
}
public static Test suite (){
public static Test suite (){
suite = new TestSuite ("AllTests");
suite = new TestSuite ("AllTests");
suite.addTest
suite.addTest


(new TestSuite (AllTests.class));
(new TestSuite (AllTests.class));
suite.addTest (StringTest.suite());
suite.addTest (StringTest.suite());
}
}
public void testAllTests () throws Exception{
public void testAllTests () throws Exception{


assertTrue (suite != null);
assertTrue (suite != null);
}
}


Example: Test Suites
public static Test suite() {
public static Test suite() {


TestSuite suite = new TestSuite(IntTest.class);
TestSuite suite = new TestSuite(IntTest.class);


suite.addTest(new TestSuite(FloatTest.class));
suite.addTest(new TestSuite(FloatTest.class));


suite.addTest(new TestSuite(BoolTest.class));
suite.addTest(new TestSuite(BoolTest.class));


return suite;
return suite;


}
}
32


Test Runners
Test Runners


TestRunners

Text
Text

Lightweight, quick quiet
Lightweight, quick quiet

Run from command line
Run from command line
java StringTest
java StringTest
.......
.......
Time: 0.05
Time: 0.05
Tests run: 7, Failures: 0, Errors: 0
Tests run: 7, Failures: 0, Errors: 0


TestRunners - Swing
TestRunners - Swing

Run with java junit.swingui.TestRunner
Run with java junit.swingui.TestRunner


Automating testing (Ant)

JUnit Task



<target name="test" depends="compile-tests">
<target name="test" depends="compile-tests">


<junit printsummary="yes" fork="yes">
<junit printsummary="yes" fork="yes">


<classpath>
<classpath>


<pathelement location="${build}" />
<pathelement location="${build}" />


<pathelement location="${build}/test" />
<pathelement location="${build}/test" />


</classpath>
</classpath>


<formatter usefile="yes" type="plain" />
<formatter usefile="yes" type="plain" />


<test name="AllTests" />
<test name="AllTests" />


</junit>
</junit>


</target>
</target>


Ant Batch mode

<target name="batchtest" depends="compile-tests">
<target name="batchtest" depends="compile-tests">


<junit printsummary="yes" fork="yes" haltonfailure="no">
<junit printsummary="yes" fork="yes" haltonfailure="no">


<classpath>
<classpath>


<pathelement location="${build.dir}" />
<pathelement location="${build.dir}" />


<pathelement location="${build.dir}/test" />
<pathelement location="${build.dir}/test" />


</classpath>
</classpath>
<formatter type="plain" usefile="yes"/>
<formatter type="plain" usefile="yes"/>


<batchtest fork="yes" todir="">
<batchtest fork="yes" todir="">


<fileset dir="${test.dir}">
<fileset dir="${test.dir}">


<include name="**/*Test.java" />
<include name="**/*Test.java" />


</fileset>
</fileset>


</batchtest>
</batchtest>


</junit>
</junit>


</target>
</target>
37


JUnit Classes
JUnit Classes


JUnit Class Diagram
39


Best Practice
Best Practice


What should I test?

Tests things which could break
Tests things which could break

Tests should succeed quietly.
Tests should succeed quietly.

Don’t print “Doing foo…done with foo!”
Don’t print “Doing foo…done with foo!”

Negative tests, exceptions and errors
Negative tests, exceptions and errors

What shouldn’t I test
What shouldn’t I test

Don’t test set/get methods
Don’t test set/get methods

Don’t test the compiler
Don’t test the compiler



Test first and what to test

Write your test first, or at least at the
Write your test first, or at least at the
same time
same time

Test what can break
Test what can break

Create new tests to show bugs then fix
Create new tests to show bugs then fix
the bug
the bug

Test driven development says write the
Test driven development says write the
test then make it pass by coding to it.
test then make it pass by coding to it.


Testing for Exceptions

public void testExpectException()

{

String s1 = null;

String s2 = new String("abcd");


try{

s1.toString();

fail("Should see null pointer");

}

catch(NullPointerException ex){

assertTrue(true);

}

}



Test then Fix

Bugs occasionally slip through (gasp!)
Bugs occasionally slip through (gasp!)

Write a test first which demonstrates the
Write a test first which demonstrates the
error. Obviously, this test is needed.
error. Obviously, this test is needed.

Now, fix the bug and watch the bar go
Now, fix the bug and watch the bar go
green!
green!

Your tests assure the bug won’t
Your tests assure the bug won’t
reappear.
reappear.


Test then Refactor
Test then Refactor

Once the code is written you want to
Once the code is written you want to
improve it.
improve it.

Changes for performance,
Changes for performance,
maintainability, readability.
maintainability, readability.

Tests help you make sure you don’t
Tests help you make sure you don’t
break it while improving it.
break it while improving it.

Small change, test, small change, test...
Small change, test, small change, test...
45


Design Patterns for
Design Patterns for
Testing
Testing


Designing for testing

Separation of interface and implementation
Separation of interface and implementation

Allows substitution of implementation to tests
Allows substitution of implementation to tests

Factory pattern
Factory pattern

Provides for abstraction of creation of
Provides for abstraction of creation of
implementations from the tests.
implementations from the tests.

Strategy pattern
Strategy pattern

Because FactoryFinder dynamically resolves
Because FactoryFinder dynamically resolves
desired factory, implementations are plugable
desired factory, implementations are plugable


Design for testing - Factories

new
new
only used in Factory
only used in Factory

Allows writing tests which can be used
Allows writing tests which can be used
across multiple implementations.
across multiple implementations.

Promotes frequent testing by writing
Promotes frequent testing by writing
tests which work against objects without
tests which work against objects without
requiring extensive setUp
requiring extensive setUp



extra-container” testing.
extra-container” testing.


Design for testing - Mock Objects

When your implementation requires a
When your implementation requires a
resource which is unavailable for testing
resource which is unavailable for testing

External system or database is simulated.
External system or database is simulated.

Another use of Factory, the mock
Another use of Factory, the mock
implementation stubs out and returns the
implementation stubs out and returns the
anticipated results from a request.
anticipated results from a request.


Testing with resources
(EJB/DB)

Use fixtures to request resource
Use fixtures to request resource
connection via factory, could be no-op.
connection via factory, could be no-op.

Use vm args or resource bundle to drive
Use vm args or resource bundle to drive
which factory is used.
which factory is used.

Data initialization/clearing handled by
Data initialization/clearing handled by
fixtures to preserve order independence
fixtures to preserve order independence
of tests.
of tests.
50


Extensions
Extensions


JUnit Extensions

JUnitReport
JUnitReport

Cactus
Cactus

JWebUnit
JWebUnit

XMLUnit
XMLUnit

MockObject
MockObject

StrutsTestCase
StrutsTestCase


JUnitReport

Apache Ant extension task
Apache Ant extension task

Uses XML and XSLT to generate HTML
Uses XML and XSLT to generate HTML


Cactus (from Jakarta)

Simple test framework for unit testing
Simple test framework for unit testing
server-side Java code
server-side Java code


JWebUnit

Framework that facilitates creation of
Framework that facilitates creation of
acceptance tests for web applications
acceptance tests for web applications


XMLUnit

Provides an XMLTestCase class which
Provides an XMLTestCase class which
enables assertions to be made about the
enables assertions to be made about the
content and structure of XML
content and structure of XML

Differences between two pieces of XML
Differences between two pieces of XML

Validity of a piece of XML
Validity of a piece of XML

Outcome of transforming a piece of XML
Outcome of transforming a piece of XML
using XSLT
using XSLT

Evaluation of an XPath expression on a piece
Evaluation of an XPath expression on a piece
of XML
of XML


Mock Objects

Generic unit testing framework whose goal
Generic unit testing framework whose goal
is to facilitate developing unit tests in the
is to facilitate developing unit tests in the
mock object style
mock object style

What is a Mock object?
What is a Mock object?

"double agent" used to test the behaviour of other
"double agent" used to test the behaviour of other
objects
objects

Dummy object which mimics the external
Dummy object which mimics the external
behaviour of a true implementation
behaviour of a true implementation

observes how other objects interact with its
observes how other objects interact with its
methods and compares actual behaviour with
methods and compares actual behaviour with
preset expectations
preset expectations


StrutsTestCase

Extends the JUnit TestCase class that
Extends the JUnit TestCase class that

Provides facilities for testing code based
Provides facilities for testing code based
on the Struts framework
on the Struts framework

You can test
You can test

implementation of your Action objects
implementation of your Action objects

mappings declarations
mappings declarations

form beans declarations
form beans declarations

forwards declarations
forwards declarations
58


JUnit Testing Framework
JUnit Testing Framework