Verifying and Documenting ADTs: Java Assertions and Javadoc

Verifying and Documenting ADTs: Java Assertions and Javadoc
CSD University of Crete
Fall 2008
Verifying and Documenting ADTs:
Javadoc, Java Assertions and JUnits
Slide 1 / 63
Fall 2008
CSD University of Crete
Documenting Java Code
z Regular Java comments:
/* … */
‹ for programmers who must read or modify your code
z “One Liners”:
// …
‹ for programmers who must read or modify your code
z Javadoc comments:
/** … */
‹ for those who must use your code
Slide 2 / 63
CSD University of Crete
Fall 2008
Comments and Documentation
z Already mentioned distinction between comments and documentation
Comments embedded in the code
• for the benefit of you and other programmers
‹ Documentation separate from the code
• for the benefit of anyone who wants to use your code
‹
z Both are essential in software of any size
traditionally completely separate
‹ but Java provides a tool to help bridge this gap…
‹
Slide 3 / 63
Fall 2008
CSD University of Crete
JavaDoc
z A tool that reads comments and produces documentation from them
Comments must be written in a particular style
‹ Documentation generated is limited to a particular style
• not complete on its own
• still need user manuals etc…
‹
Slide 4 / 63
Fall 2008
CSD University of Crete
General Form of a JavaDoc Comment (1/2)
z The first line is indented to line up with the code below the comment,
and starts with the begin-comment symbol (/**) followed by a return
z Subsequent lines start with an asterisk (*). They are indented an
additional space so the asterisks line up. A space separates the
asterisk from the descriptive text or tag that follows it
z Insert a blank comment line between the description and the list of
tags, as shown
z Insert additional blank lines to create "blocks" of related tags
/**
* This is the description part of a doc comment.
*
* @tag Comment for the tag
*/
Slide 5 / 63
CSD University of Crete
Fall 2008
General Form of a JavaDoc Comment (2/2)
z The last line begins with the end-comment symbol (*/) indented so the
asterisks line up and followed by a return
‹Note
that the end-comment symbol contains only a single asterisk (*)
z Break any doc-comment lines exceeding 80 characters in length, if
possible
‹
If you have more than one paragraph in the doc comment, separate
the paragraphs with a <p> paragraph tag
z Comments can contain HTML tags (including links)
Slide 6 / 63
Fall 2008
CSD University of Crete
First Sentence
z Should be a summary sentence, containing a concise but complete
description of the API item
z The Javadoc tool copies this first sentence to the appropriate
member, class/interface or package summary
z This sentence ends at the first period that is followed by a blank, tab,
or line terminator, or at the first tag (as defined below). For example,
this first sentence ends at "Prof.":
/**
* This is a simulation of Prof. Knuth's MIX computer.
*/
z you can work around this by typing an HTML meta-character such as
"&" or "<" immediately after the period, such as:
/**
* This is a simulation of Prof.&nbsp; Knuth's MIX computer.
*/
Slide 7 / 63
Fall 2008
CSD University of Crete
Tagged Paragraphs
z Tags that can be inserted in comments depend on what is commented:
class
• general description, cross-references, author, version
‹ field
• general description, cross-references
‹ method
• general description, cross-references, parameters, return value
‹
z Tagged Paragraphs begin with @followed by keyword
‹
End at the next tag or end of the comment
Slide 8 / 63
Fall 2008
CSD University of Crete
JavaDoc Comment Syntax
z Required syntax:
/**
* general comment
* @tag1 value for tag1
* @tag2 value for tag2
* …
* @tagn value for tagn
*/
z Anything that doesn’t conform to this syntax is ignored!
Main Tags:
‹ author:
‹ version:
‹ cross-reference:
‹ method parameter:
‹ method return value:
@author
@version
@see
@param
@return
Slide 9 / 63
Fall 2008
CSD University of Crete
@see (Cross-References)
z Classes
ClassName
e.g. @see Amoeba
z Fields
#LocalFieldName
e.g. @see #number_of_feet
ClassName#FieldName e.g. @see Mammal#number_of_feet
z Methods
#LocalMethodName
e.g. @see #sayHello
ClassName#MethodName
e.g. @see Student#sayHello
ClassName#MethodName(params)
e.g. @see Person#sayHello(String)
z Other docs
@see <a href="spec.html">Java Spec</a>
Slide 10 / 63
Fall 2008
CSD University of Crete
@author
z May be used for class and interface declarations
@author Nikos Armenatzoglou
z A documentation comment may contain more than one @author tag
@author Nikos Armenatzoglou
@author Vassilis Christophides
Slide 11 / 63
Fall 2008
CSD University of Crete
@version
z May be used for class and interface declarations
@version 493.0.1beta
z A documentation comment may contain at most one @version tag
Slide 12 / 63
Fall 2008
CSD University of Crete
@param
z May be used in comments for method and constructor declarations
@param i The begin index
z Parameters should be documented in the order in which they are
declared
Slide 13 / 63
Fall 2008
CSD University of Crete
@return
z Used to provide a short description of the return value
@return The object at the top of the stack
z May be used in documentation comments for declarations of methods
whose result type is not void
z Cannot be used in constructors (constructors do not return anything;
only create!!!)
Slide 14 / 63
Fall 2008
CSD University of Crete
@exception (or @throws)
z May be used in documentation comments for method and constructor
declarations
@exception IndexOutOfBoundsException The matrix is
too large
z The name of the class followed by a short description of when it is
thrown
Slide 15 / 63
Fall 2008
CSD University of Crete
@deprecated
z Adds a comment indicating that this API should no longer be used
(even though it may continue to work).
@deprecated deprecated-text
z Javadoc moves the deprecated-text ahead of the description, placing
it in italics and preceding it with a bold warning: "Deprecated".
z The first sentence of deprecated-text should at least tell the user
when the API was deprecated and what to use as a replacement.
Slide 16 / 63
Fall 2008
CSD University of Crete
JavaDoc Example (1/3)
/**
* The root of the Class hierarchy. Every Class in the
* system has Object as its ultimate parent. Every
* variable and method defined here is available in every
* object.
*
* @see Class
* @version 1.37, 6 Nov 2007
*/
public class Object {
…
}
Slide 17 / 63
Fall 2008
CSD University of Crete
JavaDoc Example (2/3)
/**
* Compares two Objects for equality.
* Returns a boolean that indicates whether this Object
* is equivalent to the specified Object. This method is
* used when an Object is stored in a hashtable.
*
* @param obj The Object to compare with
* @return True if these Objects are equal;
*
false otherwise
* @see
java.util.Hashtable
*/
public boolean equals (Object obj) {
return (this == obj);
}
Slide 18 / 63
Fall 2008
CSD University of Crete
JavaDoc Example (3/3)
Slide 19 / 63
Fall 2008
CSD University of Crete
Running Javadoc
z Synopsis:
javadoc [ options ] [ packagenames ] [ sourcefiles]
[ @files ]
z Example:
‹Directory
where the .html output of the javadoc will be stored: api/
‹Directories with source code:
src/ and src/folder/
javadoc -d api/ src/*.java src/folder/*.java
z For further information type “javadoc” at your command line…
Slide 20 / 63
Fall 2008
CSD University of Crete
Style Guidelines
z Be brief
‹
don’t repeat things that are obvious from names and types
z Avoid repeating subject
e.g. Gets the name.
‹ e.g. The age.
‹
Not This method gets the name
Not This field contains the age
z Use 3rd person for methods
‹e.g.
Gets the label.
Not Get the label
Slide 21 / 63
CSD University of Crete
Fall 2008
Adding Preconditions and Postconditions in Javadoc
z In JDK 1.4, we can add preconditions and postconditions as simple
Javadoc comments.
/**
* Creates a substring of this string.
*
* Precondition: 0 ≤ i < j ≤ length().
* Postcondition: Returns the substring of this string
* consisting of the characters whose indexes are i,…,j–1
* @param i The begin index
* @param j The end index
* @return The substring of this string consisting of the
* characters whose indexes are i, …, j–1
*/
public String substring (int i, int j);
Slide 22 / 63
Fall 2008
CSD University of Crete
Assertions
Slide 23 / 63
CSD University of Crete
Fall 2008
Verifying your code with assertions
z An assertion is a statement that enables you to test your assumptions
about your program
z SDK 1.4 introduces a new keyword assert, which allows the insertion
of assertions in a Java program.
z Each assertion contains a boolean expression that you believe will be
true when the assertion is executed
‹ If it is not true, the system will throw an error AssertionError
(subclass of java.lang.Error)
z Assertions can be activated during the test phase of the development
and deactivated in the production
Slide 24 / 63
Fall 2008
CSD University of Crete
Syntax
z assert assertion;
where assertion is a boolean expression
z assert assertion : expression;
assertion: a boolean expression
‹ expression: is an expression that has a value (It cannot be an
invocation of a method that is declared void)
• passes the value of expression to the appropriate
AssertionError constructor, which uses the string
representation of the value as the error's detail message.
‹
Slide 25 / 63
Fall 2008
CSD University of Crete
Why use assertions?
z By verifying that the boolean expression is indeed true, the assertion
confirms your assumptions about the behavior of your program,
increasing your confidence that the program is free of errors
z Experience has shown that writing assertions while programming is one
of the quickest and most effective ways to detect and correct bugs
Slide 26 / 63
Fall 2008
CSD University of Crete
Where to use assertions
z Internal Invariants
‹
assert that an internal invariant has actual the value that it’s
expected to have
z Control-Flow Invariants
‹
place an assertion at any location you assume will not be reached
z Preconditions, Postconditions, and Class Invariants
‹
it can help support an informal design-by-contract style of
programming
Slide 27 / 63
Fall 2008
CSD University of Crete
Internal Invariants (1/2)
z Programmers are used to write comments to indicate their
assumptions concerning a program's behavior, ex.
if (i % 3 == 0) {
...
} else if (i % 3 == 1) {
...
} else {
// We know (i % 3 == 2)
...
}
if (i % 3 == 0) {
...
} else if (i % 3 == 1) {
...
} else {
assert i % 3 == 2 : i;
...
}
Use an assertion whenever you would have written
a comment that asserts an invariant
Slide 28 / 63
Fall 2008
CSD University of Crete
Internal Invariants (2/2)
z Another good candidate for an assertion is a switch statement with no
default case.
switch(suit) {
case Suit.CLUBS:
...
break;
case Suit.DIAMONDS:
...
break;
case Suit.HEARTS:
...
break;
case Suit.SPADES:
...
}
The absence of a default case
typically indicates that a programmer
believes that one of the cases will
always be executed
default:
assert false: suit;
Slide 29 / 63
Fall 2008
CSD University of Crete
Control-Flow Invariants
z Place an assertion at any location you assume will not be reached
z For example, suppose you have a method that looks like this:
void foo() {
for (...) {
If (...)
return;
}
void foo() {
for (...) {
If (...)
return;
}
// Execution should never
// reach this point!!!
}
assert false;
}
Use this technique with discretion
If a statement is unreachable as defined in the Java Language
Specification, you will get a compile time error, if you try to assert that it is
not reached.
Slide 30 / 63
Fall 2008
CSD University of Crete
Preconditions
Assert what must be true when a method is invoked. BUT…
¾ Do not use assertions to check the parameters of a public method…
Preconditions on public methods are enforced by explicit checks
that throw particular, specified exceptions
‹ It must check its arguments whether or not assertions are enabled
‹ The assert construct does not throw an exception of the specified
type. It can throw only an AssertionError
‹
¾ Use an assertion to test a non-public method's precondition that you
believe it will be true no matter what a client does with the class.
Slide 31 / 63
Fall 2008
CSD University of Crete
Postconditions
You can test postcondition with assertions in both public and non-public
methods
/** Returns a BigInteger whose value is (this-1 mod m).
*
* @param m the modulus.
* @return this-1 mod m.
* @throws ArithmeticException m <= 0, or this BigInteger
* has no multiplicative inverse mod m (that is, this BigInteger
* is not relatively prime to m).
*/
public BigInteger modInverse (BigInteger m) {
if (m.signum <= 0)
throw new ArithmeticException("Modulus not positive: " + m);
... // Do the computation
assert ( ((this-1)*result) % m ) == 0 : this;
return result;
}
Slide 32 / 63
Fall 2008
CSD University of Crete
Class Invariants
z A class invariant is a type of internal invariant that applies to every
instance of a class at all times, except when an instance is in
transition from one consistent state to another.
z That is, a class invariant should be true before and after any method
completes
z ex. implement a balanced tree data structure
check that insertObject() method, after the end of an insertion
and before the return; statement, keeps the tree in fact balanced.
// Returns true if this tree is properly balanced
private boolean balanced() {
...
}
assert balanced();
Slide 33 / 63
Fall 2008
CSD University of Crete
Where not to use assertions
z DO NOT use assertions for:
‹
Argument checking in public methods
• Correct arguments is part of the published specifications(or contract) of a
method and must be obeyed whether assertions are enabled or disabled
• Erroneous arguments should result in an appropriate runtime exception
‹
Doing any work that your application requires for correct operation
• Assertions may be disabled, thus expression contained in an assertion
may not be evaluated
// Broken! - Action is contained in assertion
assert names.remove(null);
// Fixed - Action precedes assertion boolean
nullsRemoved = names.remove(null);
assert nullsRemoved;
//Runs whether or not asserts are enabled
3
Slide 34 / 63
CSD University of Crete
Fall 2008
Compiling Files That Use Assertions
z For the javac compiler to accept code containing assertions, you
must use the “-source 1.4” command-line option:
%> javac -source 1.4 MyClass.java
Slide 35 / 63
CSD University of Crete
Fall 2008
Enabling and Disabling Assertions
z By default, assertions are disabled at runtime
z Enable assertions at runtime:
‹
-enableassertions or –ea
z Disable assertions at runtime:
‹
-disableassertions or –da
Slide 36 / 63
Fall 2008
CSD University of Crete
Granularity
z You can specify the granularity:
‹
no arguments
• enables or disables assertions in all classes except system classes
‹
packageName
• enables or disables assertions in the named package and any
subpackages
‹
className
• enables or disables assertions in the named class
‹
...
• enables or disables assertions in the unnamed package in the current
working directory
java -ea:com.wombat.fruitbat...
-da:com.wombat.fruitbat.Brickbat BatTutor
Slide 37 / 63
Fall 2008
CSD University of Crete
The ADT Stack
z A stack is a LIFO queue of objects
z The elements of the stack have consecutive indices starting from 0 in
the topmost element
z Assuming application requirements. It must be possible:
n To make an empty stack
o To add an element to the top of a stack
p To remove the topmost element from a stack
q To test whether a stack is empty
r To access the element at the top of the stack without removing it
s To find the position of an object in the stack
Slide 38 / 63
Fall 2008
CSD University of Crete
ADT Stack Operations
z The operations defined in a possible contract of ADT Stack are:
n
o
p
q
r
s
t
Stack():
isEmpty():
peek():
search(elem):
clear():
push(elem):
pop():
Stack
Stack
Stack
Stack
Stack
Stack
-> Stack
-> Boolean
-> Object
x Object -> Int
-> Stack (void)
x Object -> Stack (void)
-> Stack (void)
Slide 39 / 63
Fall 2008
CSD University of Crete
Stack Interface
/**
* Every Class that implements a Stack ADT should
* implement this interface.
*
* @version 1.0
*/
public interface Stack {
// Method headers and comments go here
void push (Object item) throws IllegalArgumentException;
Object pop () throws IllegalStateException;
Object peek () throws IllegalStateException;
boolean isEmpty ();
void clear ();
int search (Object item);
}
Slide 40 / 63
Fall 2008
CSD University of Crete
ArrayStack
z We implement the stack itself as an Array of Objects
z The top of the stack is an integer index to the last position of the array
0
1
2
3
4
5
6
top = 3
z Make the decision that the size of the array can change dynamically
(Assumption: All stacks start with size 100)
Slide 41 / 63
Fall 2008
CSD University of Crete
ADT Stack Code
/**
* A stack implementation using Array.
* The capacity of the Array is set to default but it can
* change dynamically if needed.
*
* @version 1.0
* @author Nikos Armenatzoglou
*/
public class ArrayStack implements Stack {
// The default capacity of the Array
public final static int DEFAULT_CAPACITY = 100;
private Object stack[];
private int top;
// The stack itself
// index of the top of the
// stack.
Slide 42 / 63
Fall 2008
CSD University of Crete
ADT Stack Code
/**
* Create a stack with Default Capacity
*/
public ArrayStack() {
stack = new Object[DEFAULT_CAPACITY];
top = -1; //No items:top can’t point to anything useful
assert stack != null;
//postcondition
}
/**
* Tests if this stack is empty.
*
* @returns true if and only if this stack contains no
* items; false otherwise.
*/
public boolean isEmpty() { return top == -1; }
Slide 43 / 63
Fall 2008
CSD University of Crete
ADT Stack Code
/**
* Looks at the object at the top of this stack without
* removing it from the stack.
*
* @return the object at the top of this stack
* @throws IllegalStateException If this stack is empty.
*/
public Object peek() throws IllegalStateException {
if (isEmpty())
throw new IllegalStateException (“Stack is empty”);
assert top != -1: top;
assert stack[top] != null;
// Invariant
return stack[top]; // return a reference to the item
// on top of the stack
}
Slide 44 / 63
Fall 2008
CSD University of Crete
ADT Stack Code
/**
* Adds an item to the top of the stack.
*
* @param item the Object to be pushed onto the Stack
* @return void
* @throws IllegalArgumentException If item is null
*/
public void push(Object item) throws IllegalArgumentException{
if (item == null)
throw new IllegalArgumentException(“item cant be null”);
if (isFull())
resizeStack();
// resizeSatck would be a private
// arrayStack method
top++;
// Increment top index
stack[top] = item;
// Add item to new top position
assert stack[top] == item;
// postcondition
}
Slide 45 / 63
Fall 2008
CSD University of Crete
ADT Stack Code
/**
* Removes the object at the top of this stack and
* returns that object as the value of this function.
*
* @return The object at the top of this stack
* @throws IllegalStateException - If this stack is
* empty.
*/
public Object pop() throws IllegalStateException {
if (isEmpty()) {
throw new IllegalStateException(“Stack is empty”);
}
Object topItem = stack[top];
stack[top] = null; //Remove ref to item on stack
top--;
// increment top
return topItem;
// return the item that was popped
}
Slide 46 / 63
Fall 2008
CSD University of Crete
ADT Stack Code
/**
* Searches for the specified object in the stack and
* returns it’s position.
*
* @param obj The object to find in the stack
* @return The object’s position in this stack, -1 if
* object wasn’t found
* @throws IllegalStateException If this stack is empty.
*/
public int search(Object obj) throws IllegalStateException {
if (isEmpty())
throw new IllegalStateException (“Stack is empty”);
for (int i = 0; i < top; i++) {
if (stack[i] == obj)
return i;
}
assert i == top : i;
return -1;
}
Slide 47 / 63
Fall 2008
CSD University of Crete
ADT Stack Code
/**
* Clears this stack from all elements.
*/
public void clear() {
while (top !=-1) {
stack[top--] = null;
}
assert top == -1 : top;
// postcondition
return;
}
} // end of class ArrayStack
Slide 48 / 63
Fall 2008
CSD University of Crete
JUnit
A tool for test-driven development
Slide 49 / 63
Fall 2008
CSD University of Crete
History
z Kent Beck developed the first xUnit automated test tool for
z
z
z
z
z
Smalltalk in mid-90’s
Beck and Gamma (of design patterns Gang of Four) developed
JUnit on a flight from Zurich to Washington, D.C.
Martin Fowler: “Never in the field of software development was so
much owed by so many to so few lines of code.”
Junit has become the standard tool for Test-Driven Development
in Java (see Junit.org)
Junit test generators now part of many Java IDEs (Eclipse, BlueJ,
Jbuilder, DrJava)
Xunit tools have since been developed for many other languages
(Perl, C++, Python, Visual Basic, C#, …)
Slide 50 / 63
Fall 2008
CSD University of Crete
Why create a test suite?
z Obviously you have to test your code—right?
‹ You
can do ad hoc testing (running whatever tests occur to you
at the moment), or
‹ You can build a test suite (a thorough set of tests that can be
run at any time)
z Disadvantages of a test suite
‹ It’s a lot of extra programming
• True, but use of a good test framework can help quite a bit
‹ You don’t have time to do all that extra work
• False! Experiments repeatedly show that test suites reduce
debugging time more than the amount spent building the test
suite
z Advantages of a test suite
‹ Reduces total number of bugs in delivered code
‹ Makes code much more maintainable and refactorable
Slide 51 / 63
Fall 2008
CSD University of Crete
Architectural overview
z JUnit test framework is a
package of classes that lets
you write tests for each
method, then easily run those
tests
z TestRunner runs tests and
reports TestResults
z You test your class by
extending abstract class
TestCase
z To write test cases, you need
to know and understand the
Assert class
Slide 52 / 63
Fall 2008
CSD University of Crete
Writing a TestCase
z To start using JUnit, create a subclass of TestCase, to which
you add test methods
z Here’s a skeletal test class:
import junit.framework.TestCase;
public class TestBowl extends TestCase {
} //Test my class Bowl
z Name of class is important – should be of the form TestMyClass
or MyClassTest
z This naming convention lets TestRunner automatically find your
test classes
Slide 53 / 63
CSD University of Crete
Fall 2008
Writing methods in TestCase
z
z
z
Pattern follows programming by contract paradigm:
‹
Set up preconditions
‹
Exercise functionality being tested
‹
Check postconditions
Example:
public void testEmptyList() {
Bowl emptyBowl = new Bowl();
assertEquals(“Size of an empty list should be zero.”,
0, emptyList.size());
assertTrue(“An empty bowl should report empty.”,
emptyBowl.isEmpty());
}
Things to notice:
‹
Specific method signature – public void testWhatever()
• Allows them to be found and collected automatically by JUnit
‹
Coding follows pattern
‹
Notice the assert-type calls…
Slide 54 / 63
Fall 2008
CSD University of Crete
Assert methods
z Each assert method has parameters like these:
message, expected-value, actual-value
z Assert methods dealing with floating point numbers get an
additional argument, a tolerance
z Each assert method has an equivalent version that does not
take a message – however, this use is not recommended
because:
‹ messages helps documents the tests
‹ messages provide additional information when reading
failure logs
Slide 55 / 63
Fall 2008
CSD University of Crete
Assert methods
z
z
z
z
z
assertTrue(String message, Boolean test)
assertFalse(String message, Boolean test)
assertNull(String message, Object object)
assertNotNull(String message, Object object)
assertEquals(String message, Object expected, Object actual)
‹(uses equals method)
z assertSame(String message, Object expected, Object actual)
‹(uses == operator)
z assertNotSame(String message, Object expected, Object actual)
Slide 56 / 63
Fall 2008
CSD University of Crete
More stuff in test classes
z Suppose you want to test a class Counter
z public class CounterTest
z
z
z
z
extends junit.framework.TestCase {
‹ This is the unit test for the Counter class
public CounterTest() { } //Default constructor
protected void setUp()
‹ Test fixture creates and initializes instance variables, etc.
protected void tearDown()
‹ Releases any system resources used by the test fixture
public void testIncrement(), public void testDecrement()
‹ These methods contain tests for the Counter methods
increment(), decrement(), etc.
‹ Note capitalization convention
Slide 57 / 63
Fall 2008
CSD University of Crete
JUnit tests for Counter
public class CounterTest extends junit.framework.TestCase {
Counter counter1;
public CounterTest() { } // default constructor
protected void setUp() { // creates a (simple) test fixture
counter1 = new Counter();
}
public void testIncrement() {
assertTrue(counter1.increment() == 1);
assertTrue(counter1.increment() == 2);
}
}
public void testDecrement() {
assertTrue(counter1.decrement() == -1);
}
Note that each test begins
with a brand new counter
This means you don’t have
to worry about the order in
which the tests are run
Slide 58 / 63
Fall 2008
CSD University of Crete
TestSuites
z TestSuites collect a selection of tests to run them as a unit
z Collections automatically use TestSuites, however to specify
the order in which tests are run, write your own:
public static Test suite() {
suite.addTest(new TestBowl(“testBowl”));
suite.addTest(new TestBowl(“testAdding”));
return suite;
}
z Should seldom have to write your own TestSuites as each
method in your TestCase should be independent of all others
z Can create TestSuites that test a whole package:
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTestSuite(TestBowl.class);
suite.addTestSuite(TestFruit.class);
return suite;
}
Slide 59 / 63
Fall 2008
CSD University of Crete
JUnit in Eclipse
z To create a test class, select
File→ New→ Other... → Java,
JUnit, TestCase and enter the
name of the class you will test
Fill this in
This will be filled in
automatically
Slide 60 / 63
Fall 2008
CSD University of Crete
Running JUnit
Second, use this
pulldown menu
First, select a Test class
Third, Run As → JUnit Test
Slide 61 / 63
Fall 2008
CSD University of Crete
Results
Your results are here
Slide 62 / 63
Fall 2008
CSD University of Crete
More Information
z http://www.junit.org
‹Download
of JUnit
‹Lots of information on using JUnit
z http://www.thecoadletter.com
‹Information on Test-Driven Development
Slide 63 / 63
Was this manual useful for you? yes no
Thank you for your participation!

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

Download PDF

advertising