Title: Junit Training
1Junit Training
- Chris Yeung
- 8th Sept, 2006
2Introduction
- JUnit is a regression testing framework
- Written by Erich Gamma and Kent Beck.
- Used by developers to implement unit tests in
Java - Goal Accelerate programming and increase the
quality of code. - Part of XUnit family (HTTPUnit, Cactus), CppUnit
3Why test? Why Junit?
- Automated tests prove features
- Tests retain their value over time and allows
others to prove the software still works (as
tested). - Confidence, quality, sleep
- Effective, open source, integrated
- Get to code sooner by writing tests.
4What is Junit?
- Test framework provides tools for
- assertions
- running tests
- aggregating tests (suites)
- reporting results
- Philosophy always the same
- Let developers write tests.
- Make it easy and painless.
- Test early and test often
5Test infected
- Its a Good Thing, no penicillin needed
- Immediate gratification with build iterations
- Start with The Simplest Thing That Could
Possibly Work. - Iterate by successive application of design
pattern. - Break the cycle of more pressure fewer tests
- Reduce code captivity
- If others can test it, others can work on it.
6Junit Mechanics
- Define a subclass of TestCase.
- Override the setUp() tearDown()methods.
- Define one or more public testXXX()methods
- Exercise the object(s) under test.
- Asserts the expected results.
- Define a static suite() factory method
- Create a TestSuite containing all the tests.
- Optionally define main() to run the TestCase in
batch mode.
7Junit Mechanics
8Simple Testcase
- public class StringTest extends TestCase
- protected void setUp() / run before /
- protected void tearDown() / after /
- public void testSimpleAdd()
- String s1 new String(abcd)
- String s2 new String(abcd)
- assertTrue(Strings not equal,
- s1.equals(s2))
-
- public static void main(String args)
- junit.textui.TestRunner.run (suite ())
-
9Simple Testcase (cont.)
- public static Test suite ()
- suite new TestSuite (StringTest")
- String tests System.getProperty("tests")
- if (tests null)
- suite.addTest(new
- TestSuite(StringTest.class))
- else
- StringTokenizer tokens new
- StringTokenizer(tests, ",")
- while (tokens.hasMoreTokens())
- suite.addTest(new
- StringTest((String)tokens.nextToken()))
-
-
- return suite
10ltJUnit Reportgt
11Other assertion methods
- assertEquals(expected, actual)assertEquals(String
message, expected, actual) - This method is heavily overloaded arg1 and arg2
must be both objects or both of the same
primitive type - For objects, uses your equals method, if you have
defined it properly, as public boolean
equals(Object o)--otherwise it uses - assertSame(Object expected, Object actual)assertS
ame(String message, Object expected,
Object actual) - Asserts that two objects refer to the same object
(using ) - assertNotSame(Object expected, Object actual)asse
rtNotSame(String message, Object expected,
Object actual) - Asserts that two objects do not refer to the same
object
12Other assertion methods
- assertNull(Object object)assertNull(String
message, Object object) - Asserts that the object is null
- assertNotNull(Object object)assertNotNull(String
message, Object object) - Asserts that the object is null
- fail()fail(String message)
- Causes the test to fail and throw an
AssertionFailedError - Useful as a result of a complex test, when the
other assert methods arent quite what you want
13What should I test?
- Tests things which could break
- Tests should succeed quietly.
- Dont print Doing foodone with foo!
- Negative tests, exceptions and errors
- What shouldnt I test
- Dont test set/get methods
- Dont test the compiler
14Fixtures
- Handle common objects under test
- setup() and tearDown() used to initialize and
release common objects. - Used to insure there are no side effects between
tests. - Enforce the test independence rule, test
execution order is not guarunteed.
15Execrise
- Write a testcase to test 3 method of
java.util.ArrayList
16Test Suites
- public static void main (String args)
- junit.textui.TestRunner.run (suite ())
-
- public static Test suite ()
- suite new TestSuite ("AllTests")
- suite.addTest
- (new TestSuite (AllTests.class))
- suite.addTest (StringTest.suite())
- public void testAllTests () throws Exception
- assertTrue (suite ! null)
-
17TestRunners
- Text
- Lightweight, quick quiet
- Run from command line
- java StringTest
- .......
- Time 0.05
- Tests run 7, Failures 0, Errors 0
18TestRunners - Swing
- Run with java junit.swingui.TestRunner
19Test Runners - Eclipse
20Automating testing (Ant)
- Junit Task
-
- lttarget name"test" depends"compile-tests"gt
- ltjunit printsummary"yes" fork"yes"gt
- ltclasspathgt
- ltpathelement location"build" /gt
- ltpathelement location"build/test"
/gt - lt/classpathgt
- ltformatter usefile"yes" type"plain" /gt
- lttest name"AllTests" /gt
- lt/junitgt
- lt/targetgt
21Ant Batch mode
- lttarget name"batchtest" depends"compile-tests"gt
- ltjunit printsummary"yes" fork"yes"
haltonfailure"no"gt - ltclasspathgt
- ltpathelement location"build.dir" /gt
- ltpathelement location"build.dir/test
" /gt - lt/classpathgt
- ltformatter type"plain" usefile"yes"/gt
- ltbatchtest fork"yes" todir""gt
- ltfileset dir"test.dir"gt
- ltinclude name"/Test.java" /gt
- lt/filesetgt
- lt/batchtestgt
- lt/junitgt
- lt/targetgt
22Designing for testing
- Separation of interface and implementation
- Allows substitution of implementation to tests
- Factory pattern
- Provides for abstraction of creation of
implementations from the tests. - Strategy pattern
- Because FactoryFinder dynamically resolves
desired factory, implementations are plugable
23Design for testing - Factories
- new only used in Factory
- Allows writing tests which can be used across
multiple implementations. - Promotes frequent testing by writing tests which
work against objects without requiring extensive
setup - extra-container testing.
24Design for testing - Mock Objects
- When your implementation requires a resource
which is unavailable for testing - External system or database is simulated.
- Another use of Factory, the mock implementation
stubs out and returns the anticipated results
from a request.
25Example of using Mock Object
- import org.jmock.
- class PublisherTest extends MockObjectTestCase
- public void testOneSubscriberReceivesAMessage(
) - // set up, subscriber can be any class
- Mock mockSubscriber mock(Subscriber.clas
s) - Publisher publisher new Publisher()
- publisher.add((Subscriber)
mockSubscriber.proxy()) -
- final String message "message"
-
- // expectations
- mockSubscriber.expects(once()).method("rec
eive").with( eq(message) ) -
- // execute
- publisher.publish(message)
-
-
- Of course, you can write mock yourself by
implement interface with simple implementation
26Testing with resources (EJB/DB)
- Use fixtures to request resource connection via
factory, could be no-op. - Use vm args or resource bundle to drive which
factory is used. - Data initialization/clearing handled by fixtures
to preserve order independence of tests.
27Develop testcase with database using abstract
base class
public abstract class DatabaseTestCase extends
TestCase protected final void setUp() throws
SQLException, IOException resetData()
DefaultDataManager.setupDefaultData()
databaseSetUp() protected final
void tearDown() throws SQLException
this.databaseTearDown()
this.getConnection().close() protected
void databaseSetUp() throws SQLException,
IOException protected void
databaseTearDown() throws SQLException
public final Connection getConnection()
return currentContext.connection
28In-container unit testing
- There are tools like cactus and StrutsTestCase
- Excellent for testing
- EJB
- Servlets, Filters, Taglibs
- Container-dependent frameworks, like Struts
29JUnit Best Practices
- Separate production and test code
- But typically in the same packages
- Compile into separate trees, allowing deployment
without tests - Dont forget OO techniques, base classing
- Test-driven development
- Write failing test first
- Testing for Exceptions
- Test then Fix
- Test then Refactor
- Where should I put my test files?
30Write failing test first
- Write your test first, or at least at the same
time - Test what can break
- Create new tests to show bugs then fix the bug
- Test driven development says write the test then
make it pass by coding to it.
31Testing for Exceptions
- public void testExpectException()
-
- String s1 null
- String s2 new String("abcd")
-
- try
- s1.toString()
- fail("Should see null pointer")
-
- catch(NullPointerException ex)
-
-
32Test then Fix
- Bugs occasionally slip through (gasp!)
- Write a test first which demonstrates the error.
Obviously, this test is needed. - Now, fix the bug and watch the bar go green!
- Your tests assure the bug wont reappear.
33Test then Refactor
- Once the code is written you want to improve it.
- Changes for performance, maintainability,
readability. - Tests help you make sure you dont break it while
improving it. - Small change, test, small change, test...
34Where should I put my test files?
- You can place your tests in the same package and
directory as the classes under test. For example
- src
- com
- xyz
- SomeClass.java
- SomeClassTest.java
-
- An arguably better way is to place the tests in a
separate parallel directory structure with
package alignment. - For example
- src
- com
- xyz
- SomeClass.java
- test
- com
- xyz
- SomeClassTest.java
- These approaches allow the tests to access to all
the public and package visible methods of the
classes under test.
35Resources
- http//www.junit.org
- http//www.xprogramming.com
- http//www-106.ibm.com/developerworks/java/library
/j-junitmail/index.html - http//jakarta.apache.org/ant