You are on page 1of 51

Junit Architecture

LiuBing bliu76@yeah.net

Agenda
  

Junit Background Usage Junit Junit architecture and design pattrens Conclusion

Junit
JUnit is an open source Java testing framework used to write and run repeatable tests. It is an instance of the xUnit architecture for unit testing frameworks. JUnit features include: * Assertions for testing expected results * Test fixtures for sharing common test data * Test suites for easily organizing and running tests * Graphical and textual test runners JUnit was originally written by Erich Gamma and Kent Beck.

Martin Fowler
Never in the field of software development was so much owed by so many to so few lines of code" Martin Fowler
Martin Fowler在面向对象分析设计、UML、模式、软件开发方法学、XP、重 构...方面,都是世界顶级的专家,现为ThoughtWorks首席科学家。Martin Fowler著有4本经典书籍:“Analysis Patterns : Reusable Object Models”、 “UML Distilled: Applying the Standard Object Modeling Language”、 “Refactoring: Improving the Design of Existing Code”、“Planning Extreme Programming”。

JavaWorld

* 2002 JavaWorld Editors' Choice Awards (ECA)  Best Java Performance Monitoring/Testing Tool * 2001 JavaWorld Editors' Choice Awards (ECA)  Best Java Performance Monitoring/Testing Tool

Developer-Kent Beck  Kent Beck Kent Beck先生是软件开发方法学的泰斗,是XP (Extreme Programming)的创始人,有17年的面 向对象的编程经验。 他倡导软件开发的模式定义, CRC卡片在软件开发过程中的使用,HotDraw软件的 体系结构,基于xUnit的测试框架,重新评估了在 软件开发过程中测试优先的编程模式。 Kent Beck 是《The Smalltalk Best Practice Patterns》、 《Extreme Programming Explained》和 《Planning Extreme Programming(与Martin Fowler合著)》的作者,并且承担了XP的领导工作。 他现在是Three Rivers Institute的总裁。TRI从 事于技术和商业接合的应用研究,是是新近成立的 Agile Alliance的创始成员,Agile Alliance的使 命就是要创建更好的软件开发方法。 .

Erich Gamma Erich Gamma is the Technical Director of the Software Technology Center of ObjectTechnologyInternational (OTI) in Zurich.Developer...IBM's new platform for development tools  JFace .the Eclipse UI Framework  Eclipse Java Tooling  IBM VisualAge MicroEdition? IDE  ULC . . Erich pairs as often as possible with KentBeck to work on JavaUnit. Some of his recent projects are:  EclipseIde . He's author number 1 of the GangOfFour and feels more and more guilty that there isn't a 2nd edition.Ultra Light Client an infrastructure for thin Java clients.

communication. and courage. with enough feedback to enable the team to see where they are and to tune the practices to their unique situation. feedback. . It works by bringing the whole team together in the presence of simple practices.XP Extreme Programming is a discipline of software development based on values of simplicity.

Usage Junit .

Volume 3. Number 7 . July 1998. Java Report.JUnit Infected: Programmers Love Writing Tests see Test Infected: Programmers Love Writing Tests.

IDE        JBuilder Eclipse Forte/Netbeans IntelliJ TogetherJ Visual Age JDeveloper Integration .

JB7 .

} } .int b){ return a+b.test public class test { public int add(int a.

} public void testAdd() { test test = new test().out.assertEquals(12.TestCase public class Testtest extends TestCase { public Testtest(String s) { super(s).out.println("tearDown").println("setUp"). this. 1)).add(9. } protected void setUp() { System. } } . } protected void tearDown() { System.test.

Junit Result .

Junit Architecture & Patterns .

Goals  What are the goals of JUnit? .

Junit Architecture -Microkernel .

Microkernel extensions FrameWork .

summarize the pattern that solves it. ECOOP 94). until you have the architecture of the system.Patterns Generate Architectures The design of JUnit will be presented in a style first used in (see "Patterns Generate Architectures". Kent Beck and Ralph Johnson. We will present the architectural problem to be solved. The idea is to explain the design of a system by starting with nothing and applying patterns. and then show how the pattern was applied to JUnit . one after another.

Patterns .

Getting started. thereby letting you… queue or log requests…" Command tells us to create an object for an operation and give it a method "execute".TestCase Encapsulate a request as an object. .

TestCase .

deferring some steps to subclasses.run() Define the skeleton of an algorithm in an operation. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure .Blanks to fill in.

TestCase Here is the template method: public void run() { setUp(). tearDown(). } The default implementations of these methods do nothing: protected void runTest() { } protected void setUp() { } protected void tearDown() { } Since setUp and tearDown are intended to be overridden but will be called by the framework we declare them as protected . runTest().

test.out.assertEquals(12.SubClass TestCase public class Testtest extends TestCase { public Testtest(String s) { super(s). } protected void setUp() { System. 1)).out.add(9.println("setUp"). } protected void tearDown() { System. } } . this.println("tearDown"). } public void testAdd() { test test = new test().

Don’t care about one or many TestSuite Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly .

TestSuite public class TestSuite implements Test { private Vector fTests= new Vector(10).nextElement().shouldStop() ) break. Test test= (Test)e.addElement(test). result). e. } public void run(TestResult result) { for (Enumeration e= tests(). } } } . ) { if (result. runTest(test. public void addTest(Test test) { fTests.hasMoreElements().

JB TestSuit .

you should add a parameter to the method and pass an object that will collect the results for you. .Reporting results.TestResult Collecting Parameter suggests that when you need to collect results over several methods.

TestResult .

} catch (Throwable e) { // 2 result.addFailure(this. } } . e). } finally { tearDown().startTest(this). setUp(). e). try { runTest(). } catch (AssertionFailedError e) { //1 result.addError(this.TestCase Run public void run(TestResult result) { result.

Finally. for example. UITestResult is used by the graphical version of the JUnit Test Runner to update the graphical test status. TextTestResult collects the results and presents them in a textual form. TestResult is an extension point of the framework. an HTMLTestResult reports the results as an HTML document. Clients can define their own custom TestResult classes. .Extend TestResult JUnit comes with different implementations of TestResult. The default implementation counts the number of failures and errors and collects the results.

addElement(new TestFailure(test.AssertionFailedError An AssertionFailedError is triggered by the assert method provided by TestCase. } The AssertionFailedError is not meant to be caught by the client (a testing method inside a TestCase) but inside the Template Method TestCase. t)). Throwable t) { fErrors. } public synchronized void addFailure(Test test.addElement(new TestFailure(test. } .run(). We therefore derive AssertionFailedError from Error. Throwable t) { fFailures. public class AssertionFailedError extends Error { public AssertionFailedError () {} } The methods to collect the errors in TestResult are shown below: public synchronized void addError(Test test. Here is the simplest one: protected void assert(boolean condition) { if (!condition) throw new AssertionFailedError(). t)). JUnit provides a set of assert methods for different purposes.

AssertionFailedError .

Observer 定义对象间一种一对多的依赖关系,当 一个对象的状态发生改变时,所有依赖 于它的对象都得到通知并被自动更新。 .

addElement(new TestFailure(test. } } public synchronized void addFailure(Test test. ) { ((TestListener)e. t).hasMoreElements().TestResult public class TestResult extends Object { protected Vector fFailures. Throwable t) { fErrors. AssertionFailedError t) { fFailures. } } public synchronized void addListener(TestListener listener) { fListeners.hasMoreElements().removeElement(listener). t)). } public synchronized void removeListener(TestListener listener) { fListeners. public synchronized void addError(Test test.elements().addElement(new TestFailure(test. protected Vector fListeners. for (Enumeration e= cloneListeners(). } } . e.addElement(listener).addFailure(test.elements().nextElement()). t)).addError(test. t). e. protected Vector fErrors.nextElement()). for (Enumeration e= cloneListeners(). ) { ((TestListener)e.

*/ public void startTest(Test test). /** * A failure occurred. */ public void endTest(Test test). */ public void addError(Test test. } . */ public void addFailure(Test test. /** * A test ended. /** * A test started.TestListener public interface TestListener { /** * An error occurred. AssertionFailedError t). Throwable t).

"). fColumn= 0. } public synchronized void addFailure(Test test. } } public void endTest(Test test) { } } . Throwable t) { writer(). } public synchronized void startTest(Test test) { writer().TestRunner public class TestRunner extends BaseTestRunner { public synchronized void addError(Test test.print("E").print(". AssertionFailedError t) { writer().println().print("F"). if (fColumn++ >= 40) { writer().

Adapter Convert the interface of a class into another interface clients expect .

} }.Code public class TestMoneyEquals extends MoneyTest { public TestMoneyEquals(){ super("testMoneyEquals"). } } TestCase test= new MoneyTest("testMoneyEquals ") { protected void runTest() { testMoneyEquals(). . } protected void runTest () { testMoneyEquals().

Decorator Test TestCase TestDecorator TestSetup RepeatedTest 动态地给一个对象添加一些额外的职责。 .

TestDecorator public class TestDecorator extends Assert implements Test { protected Test fTest. public TestDecorator(Test test) { fTest= test. } public int countTestCases() { return fTest. } /** * The basic run behaviour. } } . } public void run(TestResult result) { basicRun(result).countTestCases().run(result). */ public void basicRun(TestResult result) { fTest.

TestSetup public class TestSetup extends TestDecorator { public TestSetup(Test test) { super(test). result. } public void run(final TestResult result) { Protectable p= new Protectable() { public void protect() throws Exception { setUp(). } }. basicRun(result). } } .runProtected(this. tearDown(). p).

Summary •Command •Template method •Collecting Parameter •Adapter •Pluggables Selector •Composite •Observer •Decorator •MicroKernel (SA Pattern) .

Conclusion .

. If you liked the discussion above. try the same style of presentation for your own system. both as we were developing the framework and as we try to explain it to others.Patterns We found discussing the design in terms of patterns to be invaluable. You are now in a perfect position to judge whether describing a framework with patterns is effective.

.Pattern density There is a high pattern "density" around TestCase. Once you discover what problem you are really solving. leading to a denser and denser field of patterns where they provide leverage.they should have low pattern density. Designs with high pattern density are easier to use but harder to change. which is the key abstraction of JUnit. The opposite should be true of immature frameworks . then you can begin to "compress" the solution. We have found that such a high pattern density around key abstractions is common for mature frameworks.

successes. and failures. We found that the most challenging application of JUnit was testing its own behavior. . we applied it ourselves. We found this invaluable as we continued to evolve the design of the framework.Eat your own dog food As soon as we had the base unit testing functionality implemented. A TestTest verifies that the framework reports the correct results for errors.

After all. However. we couldn’t resist adding some features but we were careful to put them into their own extensions package (test.Intersection. JUnit is written in this style. The fewer features the framework has. the easier it is to learn. and running tests automatically. It implements only those features absolutely essential to running tests. isolating the execution of tests from each other. Sure. the more likely a developer will use it. there is a counteracting force. not union There is a temptation in framework development to include every feature you can.running suites of tests. A notable member of this package is a TestDecorator allowing execution of additional code before and after a test. .extensions). you want to make the framework as valuable as possible.developers have to decide to use your framework.

We were rewarded (and are still being rewarded) for our monomania by a continuous flow of insights into JUnit. framework development. . testing. We experimented aggressively with the design. and opportunities for further articles. and nearly as much time removing duplicate functionality as we spent adding new functionality.Framework writers read their code  We spent far more time reading the JUnit code than we spent writing it. adding new classes and moving responsibility around in as many different ways as we could imagine. object design.

5.56.0035.95.9.6 . .1.9.7.06.03..9 659.:70.::5.

80908930430%089 90894306:.8 8:507 90894306:.4/7:3%089 90894306:.8 < 57490.8  57490.90/.88%0894306:..%0894306:.61 5:-..8 < < %089.4/7:3%089 90894306:.8 0903/8430%089 5:-.8 < < .90/.

069.947 %089$09:5 #050..47.80 %0890.69 %089 %089.90/%089  O   ( R  .

. < /.  > > .::  > 7/306195 ':.065.69  7/3061/.69 7/3003.95':.:':.:0%5 9:3.':.. 7/30':.069.. >  '/. 95 9:3.0. < ':.:: < 9.%:3.069.::':...:0%5 ':.%:3.69 ':.69.:095/.9:3.069..':.9:3.51:::9.< 796..1':. < ':.47345.  > 7/305.':.:. 065.:.':.

.7 7/3003.51:':.%:3..0..  .0.1 .&.069.7.&.7 ':.69< 7/30':.&.':./3 < 7/3061796.. < #96.::':./375#96.0.965  > > 9:3.0. .  > 7/306195 5.:.9:3. < :79 .65< :..3':.:.96:07.7  /.:0%5 9:3.: 7  > > . 95#96.

.7.69 6476:.4.95 .9 #3. "/:99 069..9..69  096953 &#..4.7 644.9 1./3:&30.$:22.61 6330.5#.51 '473.

43.:843 .

3 679:5.9: 6.790.65./3 /6.65696965::. 9..9.9.66.5.7.9565.1:55./6 .#.4692.:.6/5.51.6 73.4:.. 6 321.:...3.1:0::65.95: 6511:0::5.61.95:.95::0.:9 13675...9.94:6 7....4692.91:09/5.4  . 76:..

.96 44.9.0.651..9515:../:.2../:..6:/.:0..6 0.96512. '9:..95 15:.9651':.....#.99..:9.65::06446569 4..0.5 ..:  0:.99.6565.4692: '6776:. :5:..919.4692:..9.9.7.:631/.7.9515:.. 7.9515:.

... "5061:069.95 15:.367..:631.606479::.15.65 3.15:9.5115:9316 7..9 9.95:9.796139.560. :63.796/346.5/5.6.33:635 .  ..

5./.9:.':.46929769.: 5.06990. 69:3: ':.39: 651.:...0.6565.:../3.5 50. 9..4692 651.47345..3355.3.: .:69 9969: :00::: .:5. 46:.:..663.69  .65.3.51.9.7730.:65/.696516661 ::665.:....9:3.. 1:56..51.7731.1.:065.1 .

5.9...3..6559.65031 9.:.4692.5 .:76::/3 69 .65 56..9:0.960.5690.5./3..9.2.47.33 6.565 '9:. 065.9:.0.64..4692136745. 9.

95 .::.:.4692 '9.6:.4692.69555..3.55. 13679:.:.47345...9.63.3::5.:9.3 .469323. :..: ..1367933:. 5./:63.:653.9: .: 9.9:.6101..6:69 9.

..02..33 &9 06315 .64..519555 ..5.:.:964.:.9 .115:64 .67.9.11.45.06. ..656..51. .69.02./344/96.0.:.: 7.90.9:/.965 .:.:.3 061/69.65.33650.6.:6. 9555:.0..':..:.93.069.5:65: 56.:  :63..656.  .5:65:7.9::.:.

  7945. ..5195.49.5.56:3665:.1:5  .4692136745.5.:0631 4. 065.515..50.5.:::.:.1:5 9.: 40.:699. ..1.51 67769..115503.3.9./.33 /59. .115550.03: .65.9:9.5:75.46929.911 .:5.911 696946564.9 061 :75.51.65.:.9:.9. .93.5  6/0.15.9.1. 061.65.3.514659:765:/3.: :75..9.5.:4...9::3.9469.5 99.494651730.96515.