1aa41d3f04f845f7964385ccec792a85.ppt
- Количество слайдов: 35
Junit Training Chris Yeung 8 th 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), Cpp. Unit
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 Test. Case. • Override the set. Up() & tear. Down()methods. • Define or more public test. XXX()methods – Exercise the object(s) under test. – Asserts the expected results. • Define a static suite() factory method – Create a Test. Suite containing all the tests. • Optionally define main() to run the Test. Case in batch mode.
Junit Mechanics
Simple Testcase public class protected String. Test extends Test. Case { void set. Up(){ /* run before */} void tear. Down(){ /* after */ } public void test. Simple. Add() { String s 1 = new String(“abcd”); String s 2 = new String(“abcd”); assert. True(“Strings not equal”, s 1. equals(s 2)); } } public static void main(String[] args){ junit. textui. Test. Runner. run (suite ()); }
Simple Testcase (cont. ) public static Test suite (){ suite = new Test. Suite (”String. Test"); String tests = System. get. Property("tests"); if (tests == null){ suite. add. Test(new Test. Suite(String. Test. class)); }else{ String. Tokenizer tokens = new String. Tokenizer(tests, ", "); while (tokens. has. More. Tokens()){ suite. add. Test(new String. Test((String)tokens. next. Token())); } } return suite; }
Other assertion methods • assert. Equals(expected, actual) assert. Equals(String message, expected, actual) – This method is heavily overloaded: arg 1 and arg 2 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 == • assert. Same(Object expected, Object actual) assert. Same(String message, Object expected, Object actual) – Asserts that two objects refer to the same object (using ==) • assert. Not. Same(Object expected, Object actual) assert. Not. Same(String message, Object expected, Object actual) – Asserts that two objects do not refer to the same object
Other assertion methods • assert. Null(Object object) assert. Null(String message, Object object) – Asserts that the object is null • assert. Not. Null(Object object) assert. Not. Null(String message, Object object) – Asserts that the object is null • fail() fail(String message) – Causes the test to fail and throw an Assertion. Failed. Error – 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 tear. Down() 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. Array. List
Test Suites public static void main (String [] args){ junit. textui. Test. Runner. run (suite ()); } public static Test suite (){ suite = new Test. Suite ("All. Tests"); suite. add. Test (new Test. Suite (All. Tests. class)); suite. add. Test (String. Test. suite()); public void test. All. Tests () throws Exception{ assert. True (suite != null); } }
Test. Runners • Text – Lightweight, quick quiet – Run from command line java String. Test. . . . Time: 0. 05 Tests run: 7, Failures: 0, Errors: 0
Test. Runners - Swing • Run with java junit. swingui. Test. Runner
Test Runners - Eclipse
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 Factory. Finder 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 Publisher. Test extends Mock. Object. Test. Case { public void test. One. Subscriber. Receives. AMessage() { // set up, subscriber can be any class Mock mock. Subscriber = mock(Subscriber. class); Publisher publisher = new Publisher(); publisher. add((Subscriber) mock. Subscriber. proxy()); final String message = "message"; // expectations mock. Subscriber. expects(once()). method("receive"). with( eq(message) ); } } // execute publisher. publish(message); • Of course, you can write mock yourself by implement interface with simplementation
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 Database. Test. Case extends Test. Case{ protected final void set. Up() throws SQLException, IOException { reset. Data(); Default. Data. Manager. setup. Default. Data(); database. Set. Up(); } protected final void tear. Down() throws SQLException { this. database. Tear. Down(); this. get. Connection(). close(); } protected void database. Set. Up() throws SQLException, IOException { } protected void database. Tear. Down() throws SQLException { } public final Connection get. Connection() { return current. Context. connection; } }
In-container unit testing • There are tools like cactus and Struts. Test. Case • 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 test. Expect. Exception() { String s 1 = null; String s 2 = new String("abcd"); try{ s 1. to. String(); fail("Should see null pointer"); } catch(Null. Pointer. Exception 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 Some. Class. java Some. Class. Test. java An arguably better way is to place the tests in a separate parallel directory structure with package alignment. For example: src com xyz Some. Class. java test com xyz Some. Class. Test. 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: //www 106. ibm. com/developerworks/java/library /j-junitmail/index. html • http: //jakarta. apache. org/ant