Download JUnit Presentation

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Junit Training
Chris Yeung
8th Sept, 2006
Introduction
• 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
Why 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.
What 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
Test infected
• It’s 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.
Junit 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.
Junit Mechanics
Simple 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 ());
}
}
Simple 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;
}
<JUnit Report>
Other 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)
assertSame(String message, Object expected,
Object actual)
– Asserts that two objects refer to the same object (using ==)
• assertNotSame(Object expected, Object actual)
assertNotSame(String message, Object expected,
Object actual)
– Asserts that two objects do not refer to the same object
Other 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 aren’t quite what you want
What should I test?
• Tests things which could break
• Tests should succeed quietly.
– Don’t print “Doing foo…done with foo!”
– Negative tests, exceptions and errors
• What shouldn’t I test
– Don’t test set/get methods
– Don’t test the compiler
Fixtures
• 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.
Execrise
• Write a testcase to test 3 method of
java.util.ArrayList
Test 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);
}
}
TestRunners
• Text
– Lightweight, quick quiet
– Run from command line
java StringTest
.......
Time: 0.05
Tests run: 7,
Failures: 0,
Errors: 0
TestRunners - Swing
• Run with java junit.swingui.TestRunner
Test Runners - Eclipse
Automating testing (Ant)
• Junit Task
<target name="test" depends="compile-tests">
<junit printsummary="yes" fork="yes">
<classpath>
<pathelement location="${build}" />
<pathelement location="${build}/test" />
</classpath>
<formatter usefile="yes" type="plain" />
<test name="AllTests" />
</junit>
</target>
Ant Batch mode
<target name="batchtest" depends="compile-tests">
<junit printsummary="yes" fork="yes" haltonfailure="no">
<classpath>
<pathelement location="${build.dir}" />
<pathelement location="${build.dir}/test" />
</classpath>
<formatter type="plain" usefile="yes"/>
<batchtest fork="yes" todir="">
<fileset dir="${test.dir}">
<include name="**/*Test.java" />
</fileset>
</batchtest>
</junit>
</target>
Designing 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
Design 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.
Design 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.
Example 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.class);
Publisher publisher = new Publisher();
publisher.add((Subscriber) mockSubscriber.proxy());
final String message = "message";
// expectations
mockSubscriber.expects(once()).method("receive").with(
eq(message) );
// execute
publisher.publish(message);
}
}
•Of course, you can write mock yourself by
implement interface with simple implementation
Testing 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.
Develop 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;
}
}
In-container unit testing
• There are tools like cactus and
StrutsTestCase
• Excellent for testing:
– EJB
– Servlets, Filters, Taglibs
– Container-dependent frameworks, like Struts
JUnit Best Practices
•
•
•
•
•
Separate production and test code
But typically in the same packages
Compile into separate trees, allowing
deployment without tests
Don’t forget OO techniques, base classing
Test-driven development
1.
2.
3.
4.
5.
Write failing test first
Testing for Exceptions
Test then Fix
Test then Refactor
Where should I put my test files?
Write 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.
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){
}
}
Test 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 won’t reappear.
Test then Refactor
• Once the code is written you want to
improve it.
• Changes for performance, maintainability,
readability.
• Tests help you make sure you don’t break
it while improving it.
• Small change, test, small change, test...
Where 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.
Resources
• http://www.junit.org
• http://www.xprogramming.com
• http://www106.ibm.com/developerworks/java/library
/j-junitmail/index.html
• http://jakarta.apache.org/ant