Download presentation
Presentation is loading. Please wait.
Published byEsmond Morrison Modified over 9 years ago
1
The Design of JUnit Yonglei Tao
2
Test-First Development An essential element in eXtreme Programming (XP) Test is written before the code As an executable and standalone component Includes the input and checks the result Can run with an automated support Developers need to understand the interface and functionality of a component first
3
JUnit A free framework for unit testing Written by Kent Beck & Erich Gamma Helps the developer create and run individual and groups of test cases Allows test cases to be self-checked Allows to run test cases when changes are made
4
An Example Class class Money { private int amount; private String currency; public Money(int amt, String cur) { amount= amt; currency= cur; } public int amount() { return amount; } public String currency() { return currency; } public Money add(Money m) { return new Money(amount() + m.amount(), currency()); } public boolean equals(Money other) { return amount == other.amout && currency.equals(other.currency)); }
5
A Test Case public class MoneyTest { @Test public void testConstructor() { Money m1= new Money(12, "USD"); Money m2= new Money(14, "USD"); assertTrue ( !m1.equals(null) ); assertEquals ( m1, m1 ); assertEquals ( m1, new Money(12, "USD") ); assertTrue ( !m1.equals(m2) ); }
6
More Test Code a little, test a little, code a little, test a little @Test public void testAdd() { Money m1= new Money(12, "USD"); Money m2= new Money(14, "USD"); Money expected= new Money(26, "USD"); Money result= m1.add(m2); assertTrue ( expected.equals(result) ); }
7
Design Issues for JUnit A tool for unit testing Need to run test methods written by individual programmers Need to work with test classes involving different test methods Need to work with individual test cases as well as collections of test cases
8
The Command Pattern Problem Need to issue a request for an object without knowing anything about the operation being requested or the receiver of the request Need to support undo, redo, and callback Solution Encapsulate a request as an object Delegate its intended functionality to the responsible object
9
Command Class Hierarchy
10
Participating Objects nt Client
11
Consequences Extend class Command for each of the commands Let it be responsible for executing itself Let it keep info needed for undoing/redoing Support undoable operations as well as to queue or log users’ requests Also callback Adding or removing a command doesn't affect the client code
12
The Template Method Pattern Problem How to defer decision on details of an algorithm How to allow a step in an algorithm to vary Solution Let a method in a superclass defines the skeleton of an algorithm with its varying and unvarying parts Let subclasses override the varying parts in order to add their specific behavior at points of variability
13
An Example of the Template Method
14
An Example (Cont.) public class Account { public void Transaction() { A(); B(); C(); } public void A() { … } public void B() { … } public void C() { … } … } public class SavingsAccount extends Account { public void C() { … } … } public class JuniorAccount extends Account { public void A() { … } … }
15
Applicability The template method should be used To implement the invariant parts of an algorithm once and let subclasses implement behavior that can vary When common behavior among subclasses should be factored and localized in a common class to avoid code duplication To control subclass extension The template method defines hook operations Subclasses can only extend these hook operations
16
Use of the Pattern in C++, Java, …
17
Consequences Most commonly used An important pattern for framework and class library design Inverted control structure Parent class calls subclass methods Important to denote which methods Must overridden Can / Can not be overridden
18
The Adapter Pattern Problem How to resolve incompatible interfaces or provide a stable interface to similar components with different interfaces Solution Convert the original interface of a component into another interface, through an intermediate adapter object Also known as Wrapper
19
Structure
20
The Composite Pattern Problem How to allow clients to treat individual objects and compositions of objects uniformly Solution Organize objects into a tree structure that represents an aggregation hierarchy
21
Structure
22
GUI Windows and Elements How does the window hold and deal with the different items it has to manage?
23
Using the Composite Pattern
24
// Component implements default behavior for widgets when // Button, Menu, TextArea, and WidgetContainer override // Component methods as needed class WidgetContainer { Component[] myComponents; public void update() { if ( myComponents != null ) for ( int k = 0; k < myComponents.length(); k++ ) myComponents[k].update(); } Composite (Cont.)
25
Consequences Make the client simple Make it easy to add new kind of components and remove existing ones Make the design general and reusable Using the pattern when To represent part-whole hierarchies of objects Clients to be able to ignore the difference between compositions of objects and individual objects
26
Design of JUnit Serve as a framework within which developers can write and run tests Easy to learn and to use Create tests that can be performed as needed Someone other than the original author has to be able to execute the tests and interpret the results Creating test cases is expensive and the framework has to enable reusing them
27
1. Getting Started How to run test cases that are written by individual programmers? Allow to run tests in a graphical user interface or on the command-line Make manipulating tests easy
28
The Command Pattern Separating a request for executing a command from its execution User interaction object vs. domain object Allowing to invoke different implementations of a command through the same interface
29
Pattern Implementation public abstract class TestCase implements Test { private final String fName; public TestCase(String name) { fName= name; } public abstract void run(); … }
30
2. Defining Tests How to give the programmer a convenient “place” to put their test code? Need a common structure to all tests Set up test data, run some code against the data, check results, and then clean up the data
31
The Template Method Pattern Define the skeleton of an algorithm in an operation, deferring some steps to subclasses Let subclasses redefine certain steps of an algorithm without changing the algorithms’ structure Allow the programmer to consider how to write the test code without worrying about how to run it Execution of this sequence remains the same for all tests, no matter how the testing code is written
32
Pattern Implementation public class TestCase implements Test { private final String fName; public TestCase(String name) { fName= name; } public void run() { setUp(); runTest(); tearDown(); } protected void runTest() { } protected void setUp() { } protected void tearDown() { } }
33
3. Reporting Results How to collect test results? Need to capture what did and did not work after the test has run Tests usually work – only need to record the failure and a highly condensed summary of the successes
34
The Collecting Parameter Pattern Add a parameter to the method and pass an object that will collect the results from that method JUnit distinguishes between failures and errors Failures are anticipated and checked for with assertions Errors are unanticipated problems
35
Pattern Implementation public void run (TestResult result) { result.startTest(this); setUp(); try { runTest(); } catch (AssertionFailedError e) {// capture failures result.addFailure(this, e); } catch (Throwable e) { // capture errors result.addError(this, e); } finally { tearDown(); } }
36
Class TestResult public class TestResult extends Object { protected int fRunTests; protected Vector fErrors, fFailures; public TestResult() { fRunTests= 0; fErrors = new Vector(); fFailures = new Vector(); } public synchronized vid startTest (Test test) { fRunTests++; } public synchronized void addError(Test test, Throwable t) { fErrors.addElement(new TestFailure(test, t)); } public synchronized void addFailure(Test test, Throwable t) { fFailures.addElement(new TestFailure(test, t)); } }
37
4. Handling Different Test Cases How to run test cases that are implemented as different methods in the same class? A test case class may implement many different methods, each defining one test case such as testMoneyEquals or testMoneyAdd Need to make all test cases look the same from the point of view of the invoker of the test
38
The Adapter Pattern Converting the interface of a class into another interface that clients expect Using a class adapter requires to implement a subclass for each test case – too much burden on the tester So use pluggable selector as default implementation of method runTest() in an anonymous adapter class
39
Pattern Implementation protected void runTest() throws Throwable { Method runMethod= null; try { runMethod= getClass().getMethod(fName, new Class[0]); } catch (NoSuchMethodException e) { assertTrue("Method \""+fName+"\" not found", false); } try { runMethod.invoke(this, new Class[0]); } // catch InvocationTargetException & IllegalAccessException }
40
5. Dealing with One and Many How to run a single test case and report its result in a TestResult as well as run a group of test cases and report their results? Need to support suits of suits of suits of tests
41
The Composite Pattern Allowing clients treat individual objects and groups of objects uniformly
42
Class TestSuite public class TestSuite implements Test { private Vector fTests= new Vector(); public void run(TestResult result) { // delegates to its children for (Enumeration e= fTests.elements(); e.hasMoreElements(); ) { Test test = (Test) e.nextElement(); test.run(result); } } public void addTest(Test test) { fTests.addElement(test); } }
43
Summary
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.