Title: Unit Testing with JUnit
1Unit Testing with JUnit
2Many Levels of Software Testing
- Unit Testing
- Integration Testing
- Acceptance Testing
- Usability Testing
- ...
3Why Test?
- Saves time!
- Testing is more efficient than debugging.
- Prevent re-introduction of faults (regression
errors) - Validate software does it match the
specification?
4Testing is part of development
- Agile Development philosophy
- Test early.
- Test continually!
- Design
- Test
- Code
- Test
- Code
- Test
- Design
- Test
- Code
- Test-driven Development
- Many programmers write test cases first, then
code. - provides insight goals.
5Unit Testing
- Test each method of each class
- Test while you are writing the source code
- Retest whenever you modify the source code
- Agile programming recommends
- Write the test cases first!
6The Cost of Fixing "faults"
- Discover fix a defect early is much cheaper
(100X) than to fix it after code is integrated.
Figure 1.5
7The Cost of Change
- The previous figure drawn on a linear scale
Figure 1.6
8An Example
- A Coin Purse holds 1, 5, and 10 Baht coins.
- It has a capacity that is fixed when the purse is
created. - capacity is the number of coins (any type) that
purse can hold - You can insert and withdraw coins within
capacity.
insertCoin returns true if coin inserted.
9Testing without JUnit
Purse purse new Purse(10) // can hold 10
coins purse.insertCoin( new Coin( 10 ) ) if (
purse.isFull() ) out.println("ERROR
full") balance purse.getBalance( ) if (
balance ! 10 ) out.println("ERROR balance is
wrong" ) if ( purse.withdraw(5) ! null )
out.println("ERROR withdraw is wrong") if (
purse.isFull() ) out.println("ERROR is
full") if ( purse.withdraw(10) null )
out.println("ERROR couldn't withdraw 10 Baht")
10Structure of a Test Class
Class in Your Project Test Class
public class Purse / create coin purse
/ public Purse(int capacity) ... /
insert coins / public boolean insertCoins(
int tens, int fives, int ones) ... /
get value of purse / public int getBalance( )
...
public class PurseTest / test the
constructor / public void testPurse( )
... /test insert coins / public void
testInsertCoin() ... / test get value
of purse / public void testGetBalance( )
...
11Example test Purse constructor
import org.junit. // This is for JUnit
4 public PurseTest / test the constructor
/ _at_Test // _at_Test identifies a test
method public void testPurse( ) // any public
void method Purse p new Purse( 10 ) //
capacity 10 Assert.assertEquals("New Purse
should be empty", 0, p.count() ) Assert.assert
Equals("Capacity should be 10", 10,
p.getCapacity() )
optional message to print if test fails
expected result
actual result
12Example test insertCoin method
import org.junit. public PurseTest /test
insert coins / _at_Test public void insertCoins()
Purse purse new Purse( 10 ) // capacity
10 boolean result p.insertCoin( new Coin( 5 )
) Assert.assertTrue("Couldn't add coins!",
result ) Assert.assertEquals( "Balance wrong",
5, purse.getBalance( ) ) Assert.assertFalse(
"Not full yet!", purse.isFull( ) )
13JUnit 4
- JUnit 4 uses annotations to identify methods
- _at_Test indicates a test method
- _at_Before indicates a setUp method
- _at_After indicates a tearDown method
- package to import org.junit.
- Differences from JUnit 3.x
- your class doesn't need to extend TestCase
- don't need to create a TestSuite
- methods can use any names
14Contents of a Test Class (JUnit 4.x)
import org.junit.Test // JUnit 4 uses package
org.junit import static org.junit.Assert. //
import static names from "Assert" public
PurseTest // don't extend TestCase / test
the constructor / _at_Test // use _at_Test
annotation public void testPurse( ) // any
void method - no parameters Purse p new
Purse( 10 ) // capacity 10 assertEquals("New
Purse should be empty", 0, p.count()
) assertEquals("Capacity should be 10", 10,
p.capacity() ) /test insert coins
/ _at_Test public void testInsertCoins()
Purse p new Purse( 10 ) // capacity
10 boolean result p.insertCoin( new Coin( 5 )
) assertTrue("Couldn't insert coins!", result
)
15Before and After methods
_at_Before designates a method to run before each
test _at_After designates a method to run after each
test
import org.junit.Test // JUnit 4 uses package
org.junit import org.junit.Before import
org.junit.After import static org.junit.Assert.
// import names from JUnit4 "Assert" public
PurseTest // don't extend TestCase private
Purse purse _at_Before public void
runBeforeTest( ) purse new Purse( 10 )
_at_After public void runAfterTest( ) purse
null _at_Test public void testPurse( )
Assert.assertEquals("New Purse should be
empty", 0, purse.count() ) Assert.assertEquals("
Capacity should be 10", 10, purse.capacity() )
16Running JUnit 4
- CLASSPATHc/java/junit4.1/junit-4.1.jar.
- java org.junit.runner.JUnitCore PurseTest
17What can you Assert ?
- JUnit Assert class provides many assert methods
Assert.assertTrue( aBoolean ) Assert.assertTrue(
"Error message", aBoolean )
Examples
// balance should be non-negative balance
purse.getBalance( ) Assert.assertTrue( "Balance
can't be negative!", balancegt0) // should
be able to withdraw 5 Baht Money money
purse.withdraw( 5 ) Assert.assertFalse(
"withdraw should succeed", moneynull )
18AssertEquals
- Assert.assertEquals is polymorphic
assertEquals( expected, actual ) assertEquals(
"Error message", expected, actual )
can be any primitive data type, String, or Object
// test the getBalance method purse new Purse(
10 / capacity / ) int balance
purse.getBalance( ) assertEquals( "Purse should
be empty", 0, balance ) purse.insertCoins( new
Money(0,0,5) ) balance purse.getBalance(
) assertEquals( "Balance is wrong", 50, balance
)
19AssertEquals for Floating Point
- assertEquals for float and double requires a
tolerance ... an allowance for rounding errors
double root2 Math.sqrt( 2.0 ) Assert.assertEqu
als( 1.41421356, root2, 1.0E-8 )
ExpectedResult
ActualResult
Tolerance for comparison
20More Asserts... see the Javadoc
import static org.junit.Assert. public class
PurseText extends TestCase public void
getInstance( ) purse.insertCoin( new Coin(5)
) Coin m1 purse.withdraw( 5
) assertNotNull("withdraw returned null", m1
) purse.insertCoin( new Coin(10) ) // does
withdraw re-use same array? (bad) Coin m2
Store.withdraw( 10 ) assertNotSame("withdraw
returned same array", m1, m2 )
21setUp to do before each test
- in the coin purse tests, every test creates a
Purse() - this makes writing tests long and boring.
public void testPurse( ) Purse p new
Purse( 10 ) // new purse with capacity
10 Assert.assertEquals("New Purse should be
empty", 0, p.count() ) Assert.assertEquals("Cap
acity should be 10", 10, p.capacity()
) /test insert coins / public void
testInsertCoin() Purse p new Purse( 10 )
// new purse with capacity 10 boolean result
p.insertCoin( new Coin( VALUE )
) Assert.assertTrue("Couldn't insert coins!",
result )
22setUp and tearDown
- setUp - a method that is run before every test
case. - tearDown - a method that is run after every test
case.
setUp( )
testFun1( )
one test case
tearDown( )
setUp( )
another test case
testFun2( )
tearDown( )
23setUp to do before each test
- setUp( ) method is invoked before every test.
- use setUp for repetitive tasks initializing
objects vars.
public PurseTest extends TestCase private
Purse purse private static int CAPACITY
10 _at_Before protected void setUp( ) throws
Exception super( ) // always call super()
first purse new Purse( CAPACITY ) public
void testPurse( ) Assert.assertEquals("New
Purse should be empty", 0, purse.count()
)
setUp creates a new Purse for test
24Expecting an Exception?
- you can indicate that a test should throw an
exception
// this should throw a PurseFullException _at_Test(
expectedpurse.PurseFullException.class
) protected void testPurseFull() Purse p
new Purse( 1 ) p.insertCoin( new Coin(5)
) p.insertCoin( new Coin(1) ) // should
overflow
25Limit on Execution Time
- you can specify a time limit (milliseconds) for a
test - if time limit is exceeded, test fails
// this test should complete in // less than
200 milliseconds _at_Test( timeout200 ) protected
void testWithdraw() // purse and money
inserted by _at_Before method // now test if
withdraw completes on time purse.withdraw( 99
)
26tearDown to do after each test
- use tearDown for clean-up after each test
public PurseTest extends TestCase private
Purse purse private static int CAPACITY
10 _at_After protected void tearDown( ) throws
Exception super( ) purse null
27Questions about JUnit 4
- Why use
- import static org.junit.Assert.
- How do you indicate a method is a test case?
- How do you test if Math.sin(Math.PI/2) is 1 ???
- How do you test if scanner.hasNext() is true ???
28Using JUnit in Eclipse
- Eclipse includes JUnit 3.8 and 4.0 libraries
- you don't need to install JUnit separately.
- you don't need a TestSuite or main() either!
- Eclipse will manage the testing.
- Select a source file to test and then...
29Using JUnit in Eclipse (2)
- Select test options and methods to test.
30Using JUnit in Eclipse (3)
/ Test of the Purse class _at_author James
Brucker / public class PurseTest private
Purse purse private static final int CAPACITY
10 / create a new purse before each test
/ _at_Before public void setUp() throws
Exception purse new Purse( CAPACITY )
_at_Test public void testCapacity()
assertEquals("capacity wrong",
CAPACITY, purse.capacity())
Write your test cases.Eclipse can't help much
with this.
31Run JUnit in Eclipse (4)
Select the JUnit test case file and choose Run
gt Run As gt JUnit Test Results appear in a new
JUnit tab. Click on any result for details and to
go to the source code.
32What and How to Test
- Test constructors
- Test methods that implement functionality
- (usually) don't test trivial methods (getter,
setter) - What conditions to test
- "borderline" cases
- if capacity is 10, can you insert 9, 10, 11
coins? - can you withdraw 0 ?
- can you withdraw exactly amount in the purse?
- physically impossible
- can you insert negative amounts?
33JUnit 3.x
- JUnit 3.x is really old. But a lot of existing
software still uses it, so we need to know how to
read JUnit 3.x test suites. - For new code, prefer the current version of JUnit.
34Contents of a Test Class (JUnit 3.x)
import junit.framework. public PurseTest
extends TestCase / test the constructor
/ public void testPurse( ) Purse p new
Purse( 10 ) // new purse with capacity
10 Assert.assertEquals("New Purse should be
empty", 0, p.count() ) Assert.assertEquals("Capa
city should be 10", 10, p.getCapacity()
) /test insert coins / public void
testInsertCoins() Purse p new Purse( 10 )
// capacity 10 boolean result p.insertCoin(
new Coin( 5 ) ) result p.insertCoin( new
Coin( 10 ) ) Assert.assertTrue("Couldn't
insert coins", result ) Assert.assertEquals("Ba
lance is wrong", 5 10, p.getBalance()
) ...
35Running The Tests in JUnit 3 (1)
- For JUnit 3.8 your need a method a constructor
- PurseTest( string ) constructor calls super(
string ) - suite( ) creates a test suite
import junit.framework. public PurseTest
extends TestCase public PurseTest( String
testmethod ) super( testmethod ) /
create a test suite automatically / public
static Test suite( ) TestSuite suite new
TestSuite( PurseTest.class ) return suite
This is standard form of the constructor just
copy it
36Compiling and Running the Tests
- You invoke a JUnit TestRunner to run your test
suite. - JUnit 3.8 provides 3 test runners
- junit.textui.TestRunner - console test runner
- junit.awtui.TestRunner - graphical using AWT
- junit.swingui.TestRunnger - graphical using Swing
gt set CLASSPATH /java/junit3.8.2/junit.jar. gt
javac PurseTest.java gt java junit.swingui.TestRunn
er PurseTest
Name of your test class as arg.
37Another Way to Run Tests
- Call test runner from your class's main method
- don't need to invoke junit..TestRunner on cmd
line
public PurseTest extends TestCase ... public
static void main( String args )
junit.swingui.TestRunner.run( PurseTest.class
)
gt set CLASSPATH /java/junit3.8.2/junit.jar. gt
javac PurseTest.java gt java PurseTest
Name of your test class as arg.
38Selecting Tests to Run TestSuite
- In the example we created a TestSuite using
public static Test suite( ) TestSuite suite
new TestSuite( PurseTest.class ) return
suite
JUnit uses reflection to locate all methods named
"test".
- or can specify only the tests you want to run
only run these test methods
/ create a custom test suite / public static
Test suite( ) TestSuite suite new
TestSuite( ) suite.addTest( new PurseTest(
"testPurse" ) ) // test the constructor suite
.addTest( new PurseTest( "testInsertCoins") ) //
insert coins return suite
39Key Points in Using JUnit 3.x
- Your test class "extends TestCase"
- import JUnit framework
- import junit.framework.
- optional import static names to reduce typing
- import static junit.framework.Assert.
- create void methods named "test____"
- public void testGetBalance( )
- ...
-
- use assert commands to test expected results
40Changes from Junit 3 to JUnit 4
This is a JUnit 4 test class. How is it different
from Junit 3?
import org.junit.Test import static
org.junit.Assert. public PurseTest /
test the constructor / _at_Test public void
Purse( ) Purse p new Purse( 10 ) //
capacity 10 Assert.assertEquals("New Purse
should be empty", 0, p.count() ) Assert.assertE
quals("Capacity should be 10", 10, p.capacity()
) /test insert coins / _at_Test public
void insertCoins() Purse p new Purse( 10 )
// capacity 10 boolean result p.insertCoins(
new Money(4, 3, 2) ) Assert.assertTrue("Couldn'
t add coins!", result )
41JUnit 3 Adaptor for JUnit 4 test class
- You can run JUnit 3 test cases using JUnit 4 ...
import org.junit.Test import static
org.junit.Assert. // import adaptor for
JUnit 3 import junit.framework.JUnit4TestAdaptor
public PurseTest // don't extend
TestCase / JUnit 3 calls suite( ) to get a
test suite / public static junit.framework.Test
suite( ) return new JUnit4TestAdaptor(
PurseTest.class ) _at_Test ... rest of the
JUnit 4 tests ...
42Questions about JUnit 3
- What are the 2 forms of every assert( )?
- Why use
- import static junit.framework.Assert.
- What is the name of ...
- the test class for "class LineItem" ?
- your test class extends what other class?
- the test method for the LineItem constructor?
- the test method for the getItemID() method?
43References
- JUnit Home
- http//www.junit.org
- Getting software documentation
- http//www.sf.net/projects/junit
- Eclipse Netbeans include Junit, but you still
need the javadoc for API - Quick Start
- "JUnit Cookbook" (in JUnit "doc" directory)
- "JUnit 4 in 10 Minutes" (on JUnit web site)
44References
- TestNG a better JUnit
- http//www.testng.org