diff options
Diffstat (limited to 'junit4/doc')
38 files changed, 5780 insertions, 0 deletions
diff --git a/junit4/doc/ReleaseNotes4.10.html b/junit4/doc/ReleaseNotes4.10.html new file mode 100644 index 0000000..ebf4174 --- /dev/null +++ b/junit4/doc/ReleaseNotes4.10.html @@ -0,0 +1,93 @@ +<h2>Summary of Changes in version 4.10 [unreleased!]</h2> + +<p>A full summary of commits between 4.9 and 4.10 is on <a href="https://github.com/KentBeck/junit/compare/r4.9...4.10">github</a></p> + +<h3>junit-dep has correct contents</h3> + +<p>junit-dep-4.9.jar incorrectly contained hamcrest classes, which could lead to version conflicts in projects that depend on hamcrest directly. This is fixed in 4.10 [@dsaff, closing gh-309]</p> + +<h3>RuleChain</h3> + +<p>The RuleChain rule allows ordering of TestRules:</p> + +<pre><code>public static class UseRuleChain { + @Rule + public TestRule chain= RuleChain + .outerRule(new LoggingRule("outer rule") + .around(new LoggingRule("middle rule") + .around(new LoggingRule("inner rule"); + + @Test + public void example() { + assertTrue(true); + } +} +</code></pre> + +<p>writes the log</p> + +<pre><code>starting outer rule +starting middle rule +starting inner rule +finished inner rule +finished middle rule +finished outer rule +</code></pre> + +<h3>TemporaryFolder</h3> + +<ul> +<li><code>TemporaryFolder#newFolder(String... folderNames)</code> creates recursively deep temporary folders +[@rodolfoliviero, closing gh-283]</li> +<li><code>TemporaryFolder#newFile()</code> creates a randomly named new file, and <code>#newFolder()</code> creates a randomly named new folder +[@Daniel Rothmaler, closing gh-299]</li> +</ul> + +<h3>Theories</h3> + +<p>The <code>Theories</code> runner does not anticipate theory parameters that have generic +types, as reported by github#64. Fixing this won't happen until <code>Theories</code> is +moved to junit-contrib. In anticipation of this, 4.9.1 adds some of the +necessary machinery to the runner classes, and deprecates a method that only +the <code>Theories</code> runner uses, <code>FrameworkMethod</code>#producesType(). +The Common Public License that JUnit is released under is now included +in the source repository.</p> + +<p>Thanks to <code>@pholser</code> for identifying a potential resolution for github#64 +and initiating work on it.</p> + +<h3>Bug fixes</h3> + +<ul> +<li>Built-in Rules implementations +<ul> +<li>TemporaryFolder should not create files in the current working directory if applying the rule fails +[@orfjackal, fixing gh-278]</li> +<li>TestWatcher and TestWatchman should not call failed for AssumptionViolatedExceptions +[@stefanbirkner, fixing gh-296]</li> +</ul></li> +<li>Javadoc bugs +<ul> +<li>Assert documentation [@stefanbirkner, fixing gh-134]</li> +<li>ClassRule [@stefanbirkner, fixing gh-254]</li> +<li>Parameterized [@stefanbirkner, fixing gh-89]</li> +<li>Parameterized, again [@orfjackal, fixing gh-285]</li> +</ul></li> +<li>Miscellaneous +<ul> +<li>Useless code in RunAfters [@stefanbirkner, fixing gh-289]</li> +<li>Parameterized test classes should be able to have <code>@Category</code> annotations +[@dsaff, fixing gh-291]</li> +<li>Error count should be initialized in junit.tests.framework.TestListenerTest [@stefanbirkner, fixing gh-225]</li> +<li>AssertionFailedError constructor shouldn't call super with null message [@stefanbirkner, fixing gh-318]</li> +<li>Clearer error message for non-static inner test classes [@stefanbirkner, fixing gh-42]</li> +</ul></li> +</ul> + +<h3>Minor changes</h3> + +<ul> +<li>Description, Result and Failure are Serializable [@ephox-rob, closing gh-101]</li> +<li>FailOnTimeout is reusable, allowing for retrying Rules [@stefanbirkner, closing gh-265]</li> +<li>New <code>ErrorCollector.checkThat</code> overload, that allows you to specify a reason [@drothmaler, closing gh-300]</li> +</ul> diff --git a/junit4/doc/ReleaseNotes4.10.txt b/junit4/doc/ReleaseNotes4.10.txt new file mode 100644 index 0000000..ccf8625 --- /dev/null +++ b/junit4/doc/ReleaseNotes4.10.txt @@ -0,0 +1,84 @@ +## Summary of Changes in version 4.10 ## + +Thanks to a full cast of contributors of bug fixes and new features. + +A full summary of commits between 4.9 and 4.10 is on [github](https://github.com/KentBeck/junit/compare/r4.9...4.10) + +### junit-dep has correct contents ### + +junit-dep-4.9.jar incorrectly contained hamcrest classes, which could lead to version conflicts in projects that depend on hamcrest directly. This is fixed in 4.10 [@dsaff, closing gh-309] + +### RuleChain ### + +The RuleChain rule allows ordering of TestRules: + + public static class UseRuleChain { + @Rule + public TestRule chain= RuleChain + .outerRule(new LoggingRule("outer rule") + .around(new LoggingRule("middle rule") + .around(new LoggingRule("inner rule"); + + @Test + public void example() { + assertTrue(true); + } + } + +writes the log + + starting outer rule + starting middle rule + starting inner rule + finished inner rule + finished middle rule + finished outer rule + +### TemporaryFolder ### + +- `TemporaryFolder#newFolder(String... folderNames)` creates recursively deep temporary folders + [@rodolfoliviero, closing gh-283] +- `TemporaryFolder#newFile()` creates a randomly named new file, and `#newFolder()` creates a randomly named new folder + [@Daniel Rothmaler, closing gh-299] + +### Theories ### + +The `Theories` runner does not anticipate theory parameters that have generic +types, as reported by github#64. Fixing this won't happen until `Theories` is +moved to junit-contrib. In anticipation of this, 4.9.1 adds some of the +necessary machinery to the runner classes, and deprecates a method that only +the `Theories` runner uses, `FrameworkMethod`#producesType(). +The Common Public License that JUnit is released under is now included +in the source repository. + +Thanks to `@pholser` for identifying a potential resolution for github#64 +and initiating work on it. + +### Bug fixes ### + +- Built-in Rules implementations + - TemporaryFolder should not create files in the current working directory if applying the rule fails + [@orfjackal, fixing gh-278] + - TestWatcher and TestWatchman should not call failed for AssumptionViolatedExceptions + [@stefanbirkner, fixing gh-296] +- Javadoc bugs + - Assert documentation [@stefanbirkner, fixing gh-134] + - ClassRule [@stefanbirkner, fixing gh-254] + - Parameterized [@stefanbirkner, fixing gh-89] + - Parameterized, again [@orfjackal, fixing gh-285] +- Miscellaneous + - Useless code in RunAfters [@stefanbirkner, fixing gh-289] + - Parameterized test classes should be able to have `@Category` annotations + [@dsaff, fixing gh-291] + - Error count should be initialized in junit.tests.framework.TestListenerTest [@stefanbirkner, fixing gh-225] + - AssertionFailedError constructor shouldn't call super with null message [@stefanbirkner, fixing gh-318] + - Clearer error message for non-static inner test classes [@stefanbirkner, fixing gh-42] + +### Minor changes ### + +- Description, Result and Failure are Serializable [@ephox-rob, closing gh-101] +- FailOnTimeout is reusable, allowing for retrying Rules [@stefanbirkner, closing gh-265] +- New `ErrorCollector.checkThat` overload, that allows you to specify a reason [@drothmaler, closing gh-300] + + + diff --git a/junit4/doc/ReleaseNotes4.4.html b/junit4/doc/ReleaseNotes4.4.html new file mode 100644 index 0000000..3736b46 --- /dev/null +++ b/junit4/doc/ReleaseNotes4.4.html @@ -0,0 +1,271 @@ +<h2>Summary of Changes in version 4.5</h2> + +<h3>Categories</h3> + +<p>Each test method and test class can be annotated as belonging to a <em>category</em>:</p> + +<pre><code>public static class SomeUITests { + @Category(UserAvailable.class) + @Test + public void askUserToPressAKey() { } + + @Test + public void simulatePressingKey() { } +} + +@Category(InternetConnected.class) +public static class InternetTests { + @Test + public void pingServer() { } +} +</code></pre> + +<p>To run all of the tests in a particular category, you must currently explicitly create a custom request:</p> + +<pre><code>new JUnitCore().run(Request.aClass(SomeUITests.class).inCategories(UserAvailable.class)); +</code></pre> + +<p>This feature will very likely be improved before the final release of JUnit 4.5</p> + +<h3>Miscellaneous</h3> + +<ul> +<li><p><code>@Before</code> and <code>@After</code> methods are run before and after each set of attempted parameters +on a Theory</p></li> +<li><p>Refactoring removed duplication that used to exist in classes MethodRoadie and ClassRoadie</p></li> +<li><p>Exposed API <code>ParameterSignature.getType()</code></p></li> +</ul> + +<h2>Summary of Changes in version 4.4</h2> + +<p>JUnit is designed to efficiently capture developers' intentions about +their code, and quickly check their code matches those intentions. +Over the last year, we've been talking about what things developers +would like to say about their code that have been difficult in the +past, and how we can make them easier.</p> + +<p><a href="http://sourceforge.net/project/showfiles.php?group_id=15278">Download</a></p> + +<h3>assertThat</h3> + +<p>Two years ago, Joe Walnes built a <a href="http://joe.truemesh.com/blog/000511.html">new assertion mechanism</a> on top of what was +then <a href="http://www.jmock.org/download.html">JMock 1</a>. The method name was <code>assertThat</code>, and the syntax looked like this:</p> + +<pre><code>assertThat(x, is(3)); +assertThat(x, is(not(4))); +assertThat(responseString, either(containsString("color")).or(containsString("colour"))); +assertThat(myList, hasItem("3")); +</code></pre> + +<p>More generally:</p> + +<pre><code>assertThat([value], [matcher statement]); +</code></pre> + +<p>Advantages of this assertion syntax include:</p> + +<ul> +<li><p>More readable and typeable: this syntax allows you to think in terms of subject, verb, object +(assert "x is 3") rather than <code>assertEquals</code>, which uses verb, object, subject (assert "equals 3 x")</p></li> +<li><p>Combinations: any matcher statement <code>s</code> can be negated (<code>not(s)</code>), combined (<code>either(s).or(t)</code>), +mapped to a collection (<code>each(s)</code>), or used in custom combinations (<code>afterFiveSeconds(s)</code>)</p></li> +<li><p>Readable failure messages. Compare</p> + +<pre><code>assertTrue(responseString.contains("color") || responseString.contains("colour")); +// ==> failure message: +// java.lang.AssertionError: + + +assertThat(responseString, anyOf(containsString("color"), containsString("colour"))); +// ==> failure message: +// java.lang.AssertionError: +// Expected: (a string containing "color" or a string containing "colour") +// got: "Please choose a font" +</code></pre></li> +<li><p>Custom Matchers. By implementing the <code>Matcher</code> interface yourself, you can get all of the +above benefits for your own custom assertions.</p></li> +<li><p>For a more thorough description of these points, see <a href="http://joe.truemesh.com/blog/000511.html">Joe Walnes's +original post</a>.</p></li> +</ul> + +<p>We have decided to include this API directly in JUnit. +It's an extensible and readable syntax, and it enables +new features, like <a href="#assumptions">assumptions</a> and <a href="#theories">theories</a>.</p> + +<p>Some notes:</p> + +<ul> +<li>The old assert methods are never, ever, going away. Developers may +continue using the old <code>assertEquals</code>, <code>assertTrue</code>, and so on.</li> +<li><p>The second parameter of an <code>assertThat</code> statement is a <code>Matcher</code>. +We include the Matchers we want as static imports, like this:</p> + +<pre><code>import static org.hamcrest.CoreMatchers.is; +</code></pre> + +<p>or:</p> + +<pre><code>import static org.hamcrest.CoreMatchers.*; +</code></pre></li> +<li><p>Manually importing <code>Matcher</code> methods can be frustrating. <a href="http://www.eclipse.org/downloads/">Eclipse 3.3</a> includes the ability to +define +"Favorite" classes to import static methods from, which makes it easier +(Search for "Favorites" in the Preferences dialog). +We expect that support for static imports will improve in all Java IDEs in the future.</p></li> +<li><p>To allow compatibility with a wide variety of possible matchers, +we have decided to include the classes from hamcrest-core, +from the <a href="http://code.google.com/p/hamcrest/">Hamcrest</a> project. This is the first time that +third-party classes have been included in JUnit. </p></li> +<li><p>JUnit currently ships with a few matchers, defined in +<code>org.hamcrest.CoreMatchers</code> and <code>org.junit.matchers.JUnitMatchers</code>. <br /> +To use many, many more, consider downloading the <a href="http://hamcrest.googlecode.com/files/hamcrest-all-1.1.jar">full hamcrest package</a>.</p></li> +<li><p>JUnit contains special support for comparing string and array +values, giving specific information on how they differ. This is not +yet available using the <code>assertThat</code> syntax, but we hope to bring +the two assert methods into closer alignment in future releases.</p></li> +</ul> + +<p><a name="assumptions" /></p> + +<h3>Assumptions</h3> + +<p>Ideally, the developer writing a test has control of all of the forces that might cause a test to fail. +If this isn't immediately possible, making dependencies explicit can often improve a design. <br /> +For example, if a test fails when run in a different locale than the developer intended, +it can be fixed by explicitly passing a locale to the domain code.</p> + +<p>However, sometimes this is not desirable or possible. <br /> +It's good to be able to run a test against the code as it is currently written, +implicit assumptions and all, or to write a test that exposes a known bug. +For these situations, JUnit now includes the ability to express "assumptions":</p> + +<pre><code>import static org.junit.Assume.* + +@Test public void filenameIncludesUsername() { + assumeThat(File.separatorChar, is('/')); + assertThat(new User("optimus").configFileName(), is("configfiles/optimus.cfg")); +} + +@Test public void correctBehaviorWhenFilenameIsNull() { + assumeTrue(bugFixed("13356")); // bugFixed is not included in JUnit + assertThat(parse(null), is(new NullDocument())); +} +</code></pre> + +<p>With this release, a failed assumption will lead to the test being marked as passing, +regardless of what the code below the assumption may assert. +In the future, this may change, and a failed assumption may lead to the test being ignored: +however, third-party runners do not currently allow this option.</p> + +<p>We have included <code>assumeTrue</code> for convenience, but thanks to the +inclusion of Hamcrest, we do not need to create <code>assumeEquals</code>, +<code>assumeSame</code>, and other analogues to the <code>assert*</code> methods. All of +those functionalities are subsumed in <code>assumeThat</code>, with the appropriate +matcher.</p> + +<p>A failing assumption in a <code>@Before</code> or <code>@BeforeClass</code> method will have the same effect +as a failing assumption in each <code>@Test</code> method of the class.</p> + +<p><a name="theories" /></p> + +<h3>Theories</h3> + +<p>More flexible and expressive assertions, combined with the ability to +state assumptions clearly, lead to a new kind of statement of intent, +which we call a "Theory". A test captures the intended behavior in +one particular scenario. A theory captures some aspect of the +intended behavior in possibly +infinite numbers of potential scenarios. For example:</p> + +<pre><code>@RunWith(Theories.class) +public class UserTest { + @DataPoint public static String GOOD_USERNAME = "optimus"; + @DataPoint public static String USERNAME_WITH_SLASH = "optimus/prime"; + + @Theory public void filenameIncludesUsername(String username) { + assumeThat(username, not(containsString("/"))); + assertThat(new User(username).configFileName(), containsString(username)); + } +} +</code></pre> + +<p>This makes it clear that the user's filename should be included in the +config file name, only if it doesn't contain a slash. Another test +or theory might define what happens when a username does contain a slash.</p> + +<p><code>UserTest</code> will attempt to run <code>filenameIncludesUsername</code> on +every compatible <code>DataPoint</code> defined in the class. If any of the +assumptions fail, the data point is silently ignored. If all of the +assumptions pass, but an assertion fails, the test fails.</p> + +<p>The support for Theories has been absorbed from the <a href="http://popper.tigris.org">Popper</a> +project, and <a href="http://popper.tigris.org/tutorial.html">more complete documentation</a> can be found +there.</p> + +<p>Defining general statements in this way can jog the developer's memory +about other potential data points and tests, also allows <a href="http://www.junitfactory.org">automated +tools</a> to <a href="http://shareandenjoy.saff.net/2007/04/popper-and-junitfactory.html">search</a> for new, unexpected data +points that expose bugs.</p> + +<h3>Other changes</h3> + +<p>This release contains other bug fixes and new features. Among them:</p> + +<ul> +<li><p>Annotated descriptions</p> + +<p>Runner UIs, Filters, and Sorters operate on Descriptions of test +methods and test classes. These Descriptions now include the +annotations on the original Java source element, allowing for richer +display of test results, and easier development of annotation-based +filters.</p></li> +<li><p>Bug fix (1715326): assertEquals now compares all Numbers using their +native implementation of <code>equals</code>. This assertion, which passed in +4.3, will now fail:</p> + +<pre><code>assertEquals(new Integer(1), new Long(1)); +</code></pre> + +<p>Non-integer Numbers (Floats, Doubles, BigDecimals, etc), +which were compared incorrectly in 4.3, are now fixed.</p></li> +<li><p><code>assertEquals(long, long)</code> and <code>assertEquals(double, double)</code> have +been re-introduced to the <code>Assert</code> class, to take advantage of +Java's native widening conversions. Therefore, this still passes:</p> + +<pre><code>assertEquals(1, 1L); +</code></pre></li> +<li><p>The default runner for JUnit 4 test classes has been refactored. +The old version was named <code>TestClassRunner</code>, and the new is named +<code>JUnit4ClassRunner</code>. Likewise, <code>OldTestClassRunner</code> is now +<code>JUnit3ClassRunner</code>. The new design allows variations in running +individual test classes to be expressed with fewer custom classes. +For a good example, see the source to +<code>org.junit.experimental.theories.Theories</code>.</p></li> +<li><p>The rules for determining which runner is applied by default to a +test class have been simplified:</p> + +<ol> +<li><p>If the class has a <code>@RunWith</code> annotation, the annotated runner +class is used.</p></li> +<li><p>If the class can be run with the JUnit 3 test runner (it +subclasses <code>TestCase</code>, or contains a <code>public static Test suite()</code> +method), JUnit38ClassRunner is used.</p></li> +<li><p>Otherwise, JUnit4ClassRunner is used.</p></li> +</ol> + +<p>This default guess can always be overridden by an explicit +<code>@RunWith(JUnit4ClassRunner.class)</code> or +<code>@RunWith(JUnit38ClassRunner.class)</code> annotation.</p> + +<p>The old class names <code>TestClassRunner</code> and <code>OldTestClassRunner</code> +remain as deprecated.</p></li> +<li><p>Bug fix (1739095): Filters and Sorters work correctly on test +classes that contain a <code>suite</code> method like:</p> + +<pre><code>public static junit.framework.Test suite() { + return new JUnit4TestAdapter(MyTest.class); +} +</code></pre></li> +<li><p>Bug fix (1745048): @After methods are now correctly called +after a test method times out.</p></li> +</ul> diff --git a/junit4/doc/ReleaseNotes4.4.txt b/junit4/doc/ReleaseNotes4.4.txt new file mode 100644 index 0000000..98d9ddd --- /dev/null +++ b/junit4/doc/ReleaseNotes4.4.txt @@ -0,0 +1,295 @@ +## Summary of Changes in version 4.5 ## + +### Categories ### +Each test method and test class can be annotated as belonging to a _category_: + + public static class SomeUITests { + @Category(UserAvailable.class) + @Test + public void askUserToPressAKey() { } + + @Test + public void simulatePressingKey() { } + } + + @Category(InternetConnected.class) + public static class InternetTests { + @Test + public void pingServer() { } + } + +To run all of the tests in a particular category, you must currently explicitly create a custom request: + + new JUnitCore().run(Request.aClass(SomeUITests.class).inCategories(UserAvailable.class)); + +This feature will very likely be improved before the final release of JUnit 4.5 + +### Theories ### + +- `@Before` and `@After` methods are run before and after each set of attempted parameters + on a Theory, and each set of parameters is run on a new instance of the test class. + +- Exposed API's `ParameterSignature.getType()` and `ParameterSignature.getAnnotations()` + +- An array of data points can be introduced by a field or method marked with the new annotation `@DataPoints` + +- The Theories custom runner has been refactored to make it easier to extend + +### JUnit 4 Runner API ### + +- There has been a drastic rewrite of the API for custom Runners in 4.5. This + needs to be written up separately before release. + +- Tests with failed assumptions are now marked as Ignored, rather than silently passing. + This may change behavior in some client tests, and also will require some new support + on the part of IDE's. + +## Summary of Changes in version 4.4 ## + +JUnit is designed to efficiently capture developers' intentions about +their code, and quickly check their code matches those intentions. +Over the last year, we've been talking about what things developers +would like to say about their code that have been difficult in the +past, and how we can make them easier. + +[Download][] + +[Download]: http://sourceforge.net/project/showfiles.php?group_id=15278 + +### assertThat ### + +Two years ago, Joe Walnes built a [new assertion mechanism][walnes] on top of what was +then [JMock 1][]. The method name was `assertThat`, and the syntax looked like this: + +[walnes]: http://joe.truemesh.com/blog/000511.html +[JMock 1]: http://www.jmock.org/download.html + + assertThat(x, is(3)); + assertThat(x, is(not(4))); + assertThat(responseString, either(containsString("color")).or(containsString("colour"))); + assertThat(myList, hasItem("3")); + +More generally: + + assertThat([value], [matcher statement]); + +Advantages of this assertion syntax include: + +- More readable and typeable: this syntax allows you to think in terms of subject, verb, object + (assert "x is 3") rather than `assertEquals`, which uses verb, object, subject (assert "equals 3 x") + +- Combinations: any matcher statement `s` can be negated (`not(s)`), combined (`either(s).or(t)`), + mapped to a collection (`each(s)`), or used in custom combinations (`afterFiveSeconds(s)`) + +- Readable failure messages. Compare + + assertTrue(responseString.contains("color") || responseString.contains("colour")); + // ==> failure message: + // java.lang.AssertionError: + + assertThat(responseString, anyOf(containsString("color"), containsString("colour"))); + // ==> failure message: + // java.lang.AssertionError: + // Expected: (a string containing "color" or a string containing "colour") + // got: "Please choose a font" + +- Custom Matchers. By implementing the `Matcher` interface yourself, you can get all of the + above benefits for your own custom assertions. + +- For a more thorough description of these points, see [Joe Walnes's + original post][walnes]. + +We have decided to include this API directly in JUnit. +It's an extensible and readable syntax, and it enables +new features, like [assumptions][] and [theories][]. + +[assumptions]: #assumptions +[theories]: #theories + +Some notes: + +- The old assert methods are never, ever, going away. Developers may + continue using the old `assertEquals`, `assertTrue`, and so on. +- The second parameter of an `assertThat` statement is a `Matcher`. + We include the Matchers we want as static imports, like this: + + import static org.hamcrest.CoreMatchers.is; + + or: + + import static org.hamcrest.CoreMatchers.*; + +- Manually importing `Matcher` methods can be frustrating. [Eclipse 3.3][] includes the ability to + define + "Favorite" classes to import static methods from, which makes it easier + (Search for "Favorites" in the Preferences dialog). + We expect that support for static imports will improve in all Java IDEs in the future. + +[Eclipse 3.3]: http://www.eclipse.org/downloads/ + +- To allow compatibility with a wide variety of possible matchers, + we have decided to include the classes from hamcrest-core, + from the [Hamcrest][] project. This is the first time that + third-party classes have been included in JUnit. + +[Hamcrest]: http://code.google.com/p/hamcrest/ + +- JUnit currently ships with a few matchers, defined in + `org.hamcrest.CoreMatchers` and `org.junit.matchers.JUnitMatchers`. + To use many, many more, consider downloading the [full hamcrest package][]. + +[full hamcrest package]: http://hamcrest.googlecode.com/files/hamcrest-all-1.1.jar + +- JUnit contains special support for comparing string and array + values, giving specific information on how they differ. This is not + yet available using the `assertThat` syntax, but we hope to bring + the two assert methods into closer alignment in future releases. + +<a name="assumptions" /> +### Assumptions ### + +Ideally, the developer writing a test has control of all of the forces that might cause a test to fail. +If this isn't immediately possible, making dependencies explicit can often improve a design. +For example, if a test fails when run in a different locale than the developer intended, +it can be fixed by explicitly passing a locale to the domain code. + +However, sometimes this is not desirable or possible. +It's good to be able to run a test against the code as it is currently written, +implicit assumptions and all, or to write a test that exposes a known bug. +For these situations, JUnit now includes the ability to express "assumptions": + + import static org.junit.Assume.* + + @Test public void filenameIncludesUsername() { + assumeThat(File.separatorChar, is('/')); + assertThat(new User("optimus").configFileName(), is("configfiles/optimus.cfg")); + } + + @Test public void correctBehaviorWhenFilenameIsNull() { + assumeTrue(bugFixed("13356")); // bugFixed is not included in JUnit + assertThat(parse(null), is(new NullDocument())); + } + +With this release, a failed assumption will lead to the test being marked as passing, +regardless of what the code below the assumption may assert. +In the future, this may change, and a failed assumption may lead to the test being ignored: +however, third-party runners do not currently allow this option. + +We have included `assumeTrue` for convenience, but thanks to the +inclusion of Hamcrest, we do not need to create `assumeEquals`, +`assumeSame`, and other analogues to the `assert*` methods. All of +those functionalities are subsumed in `assumeThat`, with the appropriate +matcher. + +A failing assumption in a `@Before` or `@BeforeClass` method will have the same effect +as a failing assumption in each `@Test` method of the class. + +<a name="theories" /> +### Theories ### + +More flexible and expressive assertions, combined with the ability to +state assumptions clearly, lead to a new kind of statement of intent, +which we call a "Theory". A test captures the intended behavior in +one particular scenario. A theory captures some aspect of the +intended behavior in possibly +infinite numbers of potential scenarios. For example: + + @RunWith(Theories.class) + public class UserTest { + @DataPoint public static String GOOD_USERNAME = "optimus"; + @DataPoint public static String USERNAME_WITH_SLASH = "optimus/prime"; + + @Theory public void filenameIncludesUsername(String username) { + assumeThat(username, not(containsString("/"))); + assertThat(new User(username).configFileName(), containsString(username)); + } + } + +This makes it clear that the user's filename should be included in the +config file name, only if it doesn't contain a slash. Another test +or theory might define what happens when a username does contain a slash. + +`UserTest` will attempt to run `filenameIncludesUsername` on +every compatible `DataPoint` defined in the class. If any of the +assumptions fail, the data point is silently ignored. If all of the +assumptions pass, but an assertion fails, the test fails. + +The support for Theories has been absorbed from the [Popper][] +project, and [more complete documentation][popper-docs] can be found +there. + +[Popper]: http://popper.tigris.org +[popper-docs]: http://popper.tigris.org/tutorial.html + +Defining general statements in this way can jog the developer's memory +about other potential data points and tests, also allows [automated +tools][junit-factory] to [search][my-blog] for new, unexpected data +points that expose bugs. + +[junit-factory]: http://www.junitfactory.org +[my-blog]: http://shareandenjoy.saff.net/2007/04/popper-and-junitfactory.html + +### Other changes ### + +This release contains other bug fixes and new features. Among them: + +- Annotated descriptions + + Runner UIs, Filters, and Sorters operate on Descriptions of test + methods and test classes. These Descriptions now include the + annotations on the original Java source element, allowing for richer + display of test results, and easier development of annotation-based + filters. + +- Bug fix (1715326): assertEquals now compares all Numbers using their + native implementation of `equals`. This assertion, which passed in + 4.3, will now fail: + + assertEquals(new Integer(1), new Long(1)); + + Non-integer Numbers (Floats, Doubles, BigDecimals, etc), + which were compared incorrectly in 4.3, are now fixed. + +- `assertEquals(long, long)` and `assertEquals(double, double)` have + been re-introduced to the `Assert` class, to take advantage of + Java's native widening conversions. Therefore, this still passes: + + assertEquals(1, 1L); + +- The default runner for JUnit 4 test classes has been refactored. + The old version was named `TestClassRunner`, and the new is named + `JUnit4ClassRunner`. Likewise, `OldTestClassRunner` is now + `JUnit3ClassRunner`. The new design allows variations in running + individual test classes to be expressed with fewer custom classes. + For a good example, see the source to + `org.junit.experimental.theories.Theories`. + +- The rules for determining which runner is applied by default to a + test class have been simplified: + + 1. If the class has a `@RunWith` annotation, the annotated runner + class is used. + + 2. If the class can be run with the JUnit 3 test runner (it + subclasses `TestCase`, or contains a `public static Test suite()` + method), JUnit38ClassRunner is used. + + 3. Otherwise, JUnit4ClassRunner is used. + + This default guess can always be overridden by an explicit + `@RunWith(JUnit4ClassRunner.class)` or + `@RunWith(JUnit38ClassRunner.class)` annotation. + + The old class names `TestClassRunner` and `OldTestClassRunner` + remain as deprecated. + +- Bug fix (1739095): Filters and Sorters work correctly on test + classes that contain a `suite` method like: + + public static junit.framework.Test suite() { + return new JUnit4TestAdapter(MyTest.class); + } + +- Bug fix (1745048): @After methods are now correctly called + after a test method times out. + diff --git a/junit4/doc/ReleaseNotes4.5.txt b/junit4/doc/ReleaseNotes4.5.txt new file mode 100644 index 0000000..66aac70 --- /dev/null +++ b/junit4/doc/ReleaseNotes4.5.txt @@ -0,0 +1,96 @@ +## Summary of Changes in version 4.5 ## + +### Installation ### + +- We are releasing `junit-4.5.jar`, which contains all the classes + necessary to run JUnit, and `junit-dep-4.5.jar`, which leaves out + hamcrest classes, for developers who already use hamcrest outside of + JUnit. + +### Basic JUnit operation ### + +- JUnitCore now more often exits with the correct exit code (0 for + success, 1 for failure) + +- Badly formed test classes (exceptions in constructors, classes + without tests, multiple constructors, Suite without @SuiteClasses) + produce more helpful error messages + +- Test classes whose only test methods are inherited from superclasses + now run. + +- Optimization to annotation processing can cut JUnit overhead by more than half + on large test classes, especially when using Theories. [Bug 1796847] + +- A failing assumption in a constructor ignores the class + +- Correct results when comparing the string "null" with potentially + null values. [Bug 1857283] + +- Annotating a class with `@RunWith(JUnit4.class)` will always invoke the + default JUnit 4 runner in the current version of JUnit. This default changed + from `JUnit4ClassRunner` in 4.4 to `BlockJUnit4ClassRunner` in 4.5 (see below), + and may change again. + +### Extension ### + +- `BlockJUnit4Runner` is a new implementation of the standard JUnit 4 + test class functionality. In contrast to `JUnit4ClassRunner` (the old + implementation): + + - `BlockJUnit4Runner` has a much simpler implementation based on + Statements, allowing new operations to be inserted into the + appropriate point in the execution flow. + + - `BlockJUnit4Runner` is published, and extension and reuse are + encouraged, whereas `JUnit4ClassRunner` was in an internal package, + and is now deprecated. + +- `ParentRunner` is a base class for runners that iterate over + a list of "children", each an object representing a test or suite to run. + `ParentRunner` provides filtering, sorting, `@BeforeClass`, `@AfterClass`, + and method validation to subclasses. + +- `TestClass` wraps a class to be run, providing efficient, repeated access + to all methods with a given annotation. + +- The new `RunnerBuilder` API allows extending the behavior of + Suite-like custom runners. + +- `AssumptionViolatedException.toString()` is more informative + +### Extra Runners ### + +- `Parameterized.eachOne()` has been removed + +- New runner `Enclosed` runs all static inner classes of an outer class. + +### Theories ### + +- `@Before` and `@After` methods are run before and after each set of attempted parameters + on a Theory, and each set of parameters is run on a new instance of the test class. + +- Exposed API's `ParameterSignature.getType()` and `ParameterSignature.getAnnotations()` + +- An array of data points can be introduced by a field or method + marked with the new annotation `@DataPoints` + +- The Theories custom runner has been refactored to make it faster and + easier to extend + +### Development ### + +- Source has been split into directories `src/main/java` and + `src/test/java`, making it easier to exclude tests from builds, and + making JUnit more maven-friendly + +- Test classes in `org.junit.tests` have been organized into + subpackages, hopefully making finding tests easier. + +- `ResultMatchers` has more informative descriptions. + +- `TestSystem` allows testing return codes and other system-level interactions. + +### Incompatible changes ### + +- Removed Request.classes(String, Class<?>...) factory method diff --git a/junit4/doc/ReleaseNotes4.6.html b/junit4/doc/ReleaseNotes4.6.html new file mode 100644 index 0000000..36c432a --- /dev/null +++ b/junit4/doc/ReleaseNotes4.6.html @@ -0,0 +1,106 @@ +<h2>Summary of Changes in version 4.6</h2> + +<h3>Max</h3> + +<p>JUnit now includes a new experimental Core, <code>MaxCore</code>. <code>MaxCore</code> +remembers the results of previous test runs in order to run new +tests out of order. <code>MaxCore</code> prefers new tests to old tests, fast +tests to slow tests, and recently failing tests to tests that last +failed long ago. There's currently not a standard UI for running +<code>MaxCore</code> included in JUnit, but there is a UI included in the JUnit +Max Eclipse plug-in at:</p> + +<p>http://www.junitmax.com/junitmax/subscribe.html</p> + +<p>Example:</p> + +<pre><code>public static class TwoUnEqualTests { + @Test + public void slow() throws InterruptedException { + Thread.sleep(100); + fail(); + } + + @Test + public void fast() { + fail(); + } +} + +@Test +public void rememberOldRuns() { + File maxFile = new File("history.max"); + MaxCore firstMax = MaxCore.storedLocally(maxFile); + firstMax.run(TwoUnEqualTests.class); + + MaxCore useHistory= MaxCore.storedLocally(maxFile); + List<Failure> failures= useHistory.run(TwoUnEqualTests.class) + .getFailures(); + assertEquals("fast", failures.get(0).getDescription().getMethodName()); + assertEquals("slow", failures.get(1).getDescription().getMethodName()); +} +</code></pre> + +<h3>Test scheduling strategies</h3> + +<p><code>JUnitCore</code> now includes an experimental method that allows you to +specify a model of the <code>Computer</code> that runs your tests. Currently, +the only built-in Computers are the default, serial runner, and two +runners provided in the <code>ParallelRunner</code> class: +<code>ParallelRunner.classes()</code>, which runs classes in parallel, and +<code>ParallelRunner.methods()</code>, which runs classes and methods in parallel.</p> + +<p>This feature is currently less stable than MaxCore, and may be +merged with MaxCore in some way in the future.</p> + +<p>Example:</p> + +<pre><code>public static class Example { + @Test public void one() throws InterruptedException { + Thread.sleep(1000); + } + @Test public void two() throws InterruptedException { + Thread.sleep(1000); + } +} + +@Test public void testsRunInParallel() { + long start= System.currentTimeMillis(); + Result result= JUnitCore.runClasses(ParallelComputer.methods(), + Example.class); + assertTrue(result.wasSuccessful()); + long end= System.currentTimeMillis(); + assertThat(end - start, betweenInclusive(1000, 1500)); +} +</code></pre> + +<h3>Comparing double arrays</h3> + +<p>Arrays of doubles can be compared, using a delta allowance for equality:</p> + +<pre><code>@Test +public void doubleArraysAreEqual() { + assertArrayEquals(new double[] {1.0, 2.0}, new double[] {1.0, 2.0}, 0.01); +} +</code></pre> + +<h3><code>Filter.matchDescription</code> API</h3> + +<p>Since 4.0, it has been possible to run a single method using the <code>Request.method</code> +API. In 4.6, the filter that implements this is exposed as <code>Filter.matchDescription</code>.</p> + +<h3>Documentation</h3> + +<ul> +<li><p>A couple classes and packages that once had empty javadoc have been +doc'ed.</p></li> +<li><p>Added how to run JUnit from the command line to the cookbook.</p></li> +<li><p>junit-4.x.zip now contains build.xml</p></li> +</ul> + +<h3>Bug fixes</h3> + +<ul> +<li>Fixed overly permissive @DataPoint processing (2191102)</li> +<li>Fixed bug in test counting after an ignored method (2106324)</li> +</ul> diff --git a/junit4/doc/ReleaseNotes4.6.txt b/junit4/doc/ReleaseNotes4.6.txt new file mode 100644 index 0000000..a5decac --- /dev/null +++ b/junit4/doc/ReleaseNotes4.6.txt @@ -0,0 +1,100 @@ +## Summary of Changes in version 4.6 ## + +### Max ### + +JUnit now includes a new experimental Core, `MaxCore`. `MaxCore` +remembers the results of previous test runs in order to run new +tests out of order. `MaxCore` prefers new tests to old tests, fast +tests to slow tests, and recently failing tests to tests that last +failed long ago. There's currently not a standard UI for running +`MaxCore` included in JUnit, but there is a UI included in the JUnit +Max Eclipse plug-in at: + + http://www.junitmax.com/junitmax/subscribe.html + +Example: + + public static class TwoUnEqualTests { + @Test + public void slow() throws InterruptedException { + Thread.sleep(100); + fail(); + } + + @Test + public void fast() { + fail(); + } + } + + @Test + public void rememberOldRuns() { + File maxFile = new File("history.max"); + MaxCore firstMax = MaxCore.storedLocally(maxFile); + firstMax.run(TwoUnEqualTests.class); + + MaxCore useHistory= MaxCore.storedLocally(maxFile); + List<Failure> failures= useHistory.run(TwoUnEqualTests.class) + .getFailures(); + assertEquals("fast", failures.get(0).getDescription().getMethodName()); + assertEquals("slow", failures.get(1).getDescription().getMethodName()); + } + +### Test scheduling strategies ### + +`JUnitCore` now includes an experimental method that allows you to +specify a model of the `Computer` that runs your tests. Currently, +the only built-in Computers are the default, serial runner, and two +runners provided in the `ParallelRunner` class: +`ParallelRunner.classes()`, which runs classes in parallel, and +`ParallelRunner.methods()`, which runs classes and methods in parallel. + +This feature is currently less stable than MaxCore, and may be +merged with MaxCore in some way in the future. + +Example: + + public static class Example { + @Test public void one() throws InterruptedException { + Thread.sleep(1000); + } + @Test public void two() throws InterruptedException { + Thread.sleep(1000); + } + } + + @Test public void testsRunInParallel() { + long start= System.currentTimeMillis(); + Result result= JUnitCore.runClasses(ParallelComputer.methods(), + Example.class); + assertTrue(result.wasSuccessful()); + long end= System.currentTimeMillis(); + assertThat(end - start, betweenInclusive(1000, 1500)); + } + +### Comparing double arrays ### + +Arrays of doubles can be compared, using a delta allowance for equality: + + @Test + public void doubleArraysAreEqual() { + assertArrayEquals(new double[] {1.0, 2.0}, new double[] {1.0, 2.0}, 0.01); + } + +### `Filter.matchDescription` API ### + +Since 4.0, it has been possible to run a single method using the `Request.method` +API. In 4.6, the filter that implements this is exposed as `Filter.matchDescription`. + +### Documentation ### + +- A couple classes and packages that once had empty javadoc have been + doc'ed. + +- Added how to run JUnit from the command line to the cookbook. + +- junit-4.x.zip now contains build.xml + +### Bug fixes ### +- Fixed overly permissive @DataPoint processing (2191102) +- Fixed bug in test counting after an ignored method (2106324) diff --git a/junit4/doc/ReleaseNotes4.7.html b/junit4/doc/ReleaseNotes4.7.html new file mode 100644 index 0000000..69b66c6 --- /dev/null +++ b/junit4/doc/ReleaseNotes4.7.html @@ -0,0 +1,229 @@ +<h2>Summary of Changes in version 4.7</h2> + +<h3>Rules</h3> + +<ul> +<li><p>Rules allow very flexible addition or redefinition of the behavior +of each test method in a test class. Testers can reuse or extend one of the +provided Rules below, or write their own.</p> + +<p>For more on this feature, see http://www.threeriversinstitute.org/blog/?p=155</p></li> +<li><p>The TemporaryFolder Rule allows creation of files and folders +that are guaranteed to be deleted when the test method finishes +(whether it passes or fails):</p> + +<p>public static class HasTempFolder { + @Rule + public TemporaryFolder folder= new TemporaryFolder();</p> + +<pre><code>@Test +public void testUsingTempFolder() throws IOException { + File createdFile= folder.newFile("myfile.txt"); + File createdFolder= folder.newFolder("subfolder"); + // ... +} +</code></pre> + +<p>}</p></li> +<li><p>ExternalResource is a base class for Rules (like TemporaryFolder) +that set up an external resource before a test (a file, socket, server, +database connection, etc.), and guarantee to tear it down afterward:</p> + +<p>public static class UsesExternalResource { + Server myServer = new Server();</p> + +<pre><code>@Rule public ExternalResource resource = new ExternalResource() { + @Override + protected void before() throws Throwable { + myServer.connect(); + }; + + +<pre><code>@Override +protected void after() { + myServer.disconnect(); +}; +</code></pre> + +}; + + +@Test public void testFoo() { + new Client().run(myServer); +} +</code></pre> + +<p>}</p></li> +<li><p>The ErrorCollector Rule allows execution of a test to continue +after the first problem is found (for example, to collect <em>all</em> the +incorrect rows in a table, and report them all at once):</p> + +<p>public static class UsesErrorCollectorTwice { + @Rule + public ErrorCollector collector= new ErrorCollector();</p> + +<pre><code>@Test public void example() { + collector.addError(new Throwable("first thing went wrong")); + collector.addError(new Throwable("second thing went wrong")); +} +</code></pre> + +<p>}</p></li> +<li><p>Verifier is a base class for Rules like ErrorCollector, which +can turn otherwise passing test methods into failing tests if a verification +check is failed</p> + +<p>public static class ErrorLogVerifier() { + private ErrorLog errorLog = new ErrorLog();</p> + +<p>@Rule + public MethodRule verifier = new Verifier() { + @Override public void verify() { + assertTrue(errorLog.isEmpty()); + } + }</p> + +<p>@Test public void testThatMightWriteErrorLog() { + // ... + } +}</p></li> +<li><p>TestWatchman is a base class for Rules that take note +of the testing action, without modifying it. +For example, this class will keep a log of each passing and failing +test:</p> + +<p>public static class WatchmanTest { + private static String watchedLog;</p> + +<pre><code>@Rule +public MethodRule watchman= new TestWatchman() { + @Override + public void failed(Throwable e, FrameworkMethod method) { + watchedLog+= method.getName() + " " + + e.getClass().getSimpleName() + "\n"; + } + + +<pre><code>@Override +public void succeeded(FrameworkMethod method) { + watchedLog+= method.getName() + " " + "success!\n"; +} +</code></pre> + +}; + + +@Test +public void fails() { + fail(); +} + + +@Test +public void succeeds() { +} +</code></pre> + +<p>}</p></li> +<li><p>The TestName Rule makes the current test name available inside test methods:</p> + +<p>public class NameRuleTest { + @Rule public TestName name = new TestName();</p> + +<pre><code>@Test public void testA() { + assertEquals("testA", name.getMethodName()); +} + + +@Test public void testB() { + assertEquals("testB", name.getMethodName()); +} +</code></pre> + +<p>}</p></li> +<li><p>The Timeout Rule applies the same timeout to all test methods in a class:</p> + +<p>public static class HasGlobalTimeout { + public static String log;</p> + +<pre><code>@Rule public MethodRule globalTimeout = new Timeout(20); + + +@Test public void testInfiniteLoop1() { + log+= "ran1"; + for(;;) {} +} + + +@Test public void testInfiniteLoop2() { + log+= "ran2"; + for(;;) {} +} +</code></pre> + +<p>}</p></li> +<li><p>The ExpectedException Rule allows in-test specification +of expected exception types and messages:</p> + +<p>public static class HasExpectedException { + @Rule + public ExpectedException thrown= ExpectedException.none();</p> + +<pre><code>@Test +public void throwsNothing() { + + +} + + +@Test +public void throwsNullPointerException() { + thrown.expect(NullPointerException.class); + throw new NullPointerException(); +} + + +@Test +public void throwsNullPointerExceptionWithMessage() { + thrown.expect(NullPointerException.class); + thrown.expectMessage("happened?"); + thrown.expectMessage(startsWith("What")); + throw new NullPointerException("What happened?"); +} +</code></pre> + +<p>}</p></li> +</ul> + +<h3>Timeouts</h3> + +<ul> +<li>Tests that time out now show the stack trace of the test thread.</li> +</ul> + +<h3>Matchers</h3> + +<ul> +<li>Due to typing incompatibilities, JUnit is still including the 1.1 release +of hamcrest. This is not a change from 4.6, but is a change from +pre-beta releases of 4.7. Due to this incompatibility, tests using +Hamcrest 1.2 must still use the MatcherAssert.assertThat method from +Hamcrest, not Assert.assertThat from JUnit.</li> +</ul> + +<h3>Docs</h3> + +<ul> +<li>Javadocs now link to online JDK javadocs (bug 2090230)</li> +<li>Parameterized runner javadocs improved (bug 2186792)</li> +<li>Fixed Javadoc code sample for AfterClass (2126279)</li> +<li>Fixed Javadoc for assertArraysEqual(float[], float[])</li> +</ul> + +<h3>Bug fixes</h3> + +<ul> +<li>Fixed: BaseTestRunner.getTest() requires class to extend TestCase (1812200)</li> +<li>Fixed: Suite does not allow for inheritance in annotations (2783118)</li> +<li>Fixed: ParallelComputer skipped tests that took longer than 2 seconds</li> +</ul> diff --git a/junit4/doc/ReleaseNotes4.7.txt b/junit4/doc/ReleaseNotes4.7.txt new file mode 100644 index 0000000..11b70c1 --- /dev/null +++ b/junit4/doc/ReleaseNotes4.7.txt @@ -0,0 +1,194 @@ +## Summary of Changes in version 4.7 ## + +### Rules ### + +- Rules allow very flexible addition or redefinition of the behavior + of each test method in a test class. Testers can reuse or extend one of the + provided Rules below, or write their own. + + For more on this feature, see http://www.threeriversinstitute.org/blog/?p=155 + +- The TemporaryFolder Rule allows creation of files and folders + that are guaranteed to be deleted when the test method finishes + (whether it passes or fails): + + public static class HasTempFolder { + @Rule + public TemporaryFolder folder= new TemporaryFolder(); + + @Test + public void testUsingTempFolder() throws IOException { + File createdFile= folder.newFile("myfile.txt"); + File createdFolder= folder.newFolder("subfolder"); + // ... + } + } + +- ExternalResource is a base class for Rules (like TemporaryFolder) + that set up an external resource before a test (a file, socket, server, + database connection, etc.), and guarantee to tear it down afterward: + + public static class UsesExternalResource { + Server myServer = new Server(); + + @Rule public ExternalResource resource = new ExternalResource() { + @Override + protected void before() throws Throwable { + myServer.connect(); + }; + + @Override + protected void after() { + myServer.disconnect(); + }; + }; + + @Test public void testFoo() { + new Client().run(myServer); + } + } + +- The ErrorCollector Rule allows execution of a test to continue + after the first problem is found (for example, to collect _all_ the + incorrect rows in a table, and report them all at once): + + public static class UsesErrorCollectorTwice { + @Rule + public ErrorCollector collector= new ErrorCollector(); + + @Test public void example() { + collector.addError(new Throwable("first thing went wrong")); + collector.addError(new Throwable("second thing went wrong")); + } + } + +- Verifier is a base class for Rules like ErrorCollector, which + can turn otherwise passing test methods into failing tests if a verification + check is failed + + public static class ErrorLogVerifier() { + private ErrorLog errorLog = new ErrorLog(); + + @Rule + public MethodRule verifier = new Verifier() { + @Override public void verify() { + assertTrue(errorLog.isEmpty()); + } + } + + @Test public void testThatMightWriteErrorLog() { + // ... + } + } + +- TestWatchman is a base class for Rules that take note + of the testing action, without modifying it. + For example, this class will keep a log of each passing and failing + test: + + public static class WatchmanTest { + private static String watchedLog; + + @Rule + public MethodRule watchman= new TestWatchman() { + @Override + public void failed(Throwable e, FrameworkMethod method) { + watchedLog+= method.getName() + " " + + e.getClass().getSimpleName() + "\n"; + } + + @Override + public void succeeded(FrameworkMethod method) { + watchedLog+= method.getName() + " " + "success!\n"; + } + }; + + @Test + public void fails() { + fail(); + } + + @Test + public void succeeds() { + } + } + +- The TestName Rule makes the current test name available inside test methods: + + public class NameRuleTest { + @Rule public TestName name = new TestName(); + + @Test public void testA() { + assertEquals("testA", name.getMethodName()); + } + + @Test public void testB() { + assertEquals("testB", name.getMethodName()); + } + } + +- The Timeout Rule applies the same timeout to all test methods in a class: + + public static class HasGlobalTimeout { + public static String log; + + @Rule public MethodRule globalTimeout = new Timeout(20); + + @Test public void testInfiniteLoop1() { + log+= "ran1"; + for(;;) {} + } + + @Test public void testInfiniteLoop2() { + log+= "ran2"; + for(;;) {} + } + } + +- The ExpectedException Rule allows in-test specification + of expected exception types and messages: + + public static class HasExpectedException { + @Rule + public ExpectedException thrown= ExpectedException.none(); + + @Test + public void throwsNothing() { + + } + + @Test + public void throwsNullPointerException() { + thrown.expect(NullPointerException.class); + throw new NullPointerException(); + } + + @Test + public void throwsNullPointerExceptionWithMessage() { + thrown.expect(NullPointerException.class); + thrown.expectMessage("happened?"); + thrown.expectMessage(startsWith("What")); + throw new NullPointerException("What happened?"); + } + } + +### Timeouts ### +- Tests that time out now show the stack trace of the test thread. + +### Matchers ### +- Due to typing incompatibilities, JUnit is still including the 1.1 release + of hamcrest. This is not a change from 4.6, but is a change from + pre-beta releases of 4.7. Due to this incompatibility, tests using + Hamcrest 1.2 must still use the MatcherAssert.assertThat method from + Hamcrest, not Assert.assertThat from JUnit. + +### Docs ### +- Javadocs now link to online JDK javadocs (bug 2090230) +- Parameterized runner javadocs improved (bug 2186792) +- Fixed Javadoc code sample for AfterClass (2126279) +- Fixed Javadoc for assertArraysEqual(float[], float[]) + +### Bug fixes ### +- Fixed: BaseTestRunner.getTest() requires class to extend TestCase (1812200) +- Fixed: Suite does not allow for inheritance in annotations (2783118) +- Fixed: ParallelComputer skipped tests that took longer than 2 seconds diff --git a/junit4/doc/ReleaseNotes4.8.1.html b/junit4/doc/ReleaseNotes4.8.1.html new file mode 100644 index 0000000..32e36a6 --- /dev/null +++ b/junit4/doc/ReleaseNotes4.8.1.html @@ -0,0 +1,9 @@ +<h2>Summary of Changes in version 4.8.1</h2> + +<p>This was a quick bugfix release for an important bug</p> + +<h3>Bug fixes</h3> + +<ul> +<li>github#61: Category annotations on classes were not honored.</li> +</ul> diff --git a/junit4/doc/ReleaseNotes4.8.1.txt b/junit4/doc/ReleaseNotes4.8.1.txt new file mode 100644 index 0000000..bc13f26 --- /dev/null +++ b/junit4/doc/ReleaseNotes4.8.1.txt @@ -0,0 +1,7 @@ +## Summary of Changes in version 4.8.1 ## + +This was a quick bugfix release for an important bug + +### Bug fixes ### + +- github#61: Category annotations on classes were not honored.
\ No newline at end of file diff --git a/junit4/doc/ReleaseNotes4.8.2.html b/junit4/doc/ReleaseNotes4.8.2.html new file mode 100644 index 0000000..273f03b --- /dev/null +++ b/junit4/doc/ReleaseNotes4.8.2.html @@ -0,0 +1,10 @@ +<h2>Summary of Changes in version 4.8.2</h2> + +<p>This was a quick bugfix release</p> + +<h3>Bug fixes</h3> + +<ul> +<li>github#96: TestSuite(MyTestCase.class) should dynamically detect if MyTestCase +is a TestCase</li> +</ul> diff --git a/junit4/doc/ReleaseNotes4.8.2.txt b/junit4/doc/ReleaseNotes4.8.2.txt new file mode 100644 index 0000000..8631275 --- /dev/null +++ b/junit4/doc/ReleaseNotes4.8.2.txt @@ -0,0 +1,8 @@ +## Summary of Changes in version 4.8.2 ## + +This was a quick bugfix release + +### Bug fixes ### + +- github#96: TestSuite(MyTestCase.class) should dynamically detect if MyTestCase + is a TestCase diff --git a/junit4/doc/ReleaseNotes4.8.html b/junit4/doc/ReleaseNotes4.8.html new file mode 100644 index 0000000..086f5d0 --- /dev/null +++ b/junit4/doc/ReleaseNotes4.8.html @@ -0,0 +1,59 @@ +<h2>Summary of Changes in version 4.8</h2> + +<h3>Categories</h3> + +<p>From a given set of test classes, the <code>Categories</code> runner +runs only the classes and methods +that are annotated with either the category given with the <code>@IncludeCategory</code> +annotation, or a subtype of that category. Either classes or interfaces can be +used as categories. Subtyping works, so if you say <code>@IncludeCategory(SuperClass.class)</code>, +a test marked <code>@Category({SubClass.class})</code> will be run.</p> + +<p>You can also exclude categories by using the <code>@ExcludeCategory</code> annotation</p> + +<p>Example:</p> + +<pre><code>public interface FastTests { /* category marker */ } +public interface SlowTests { /* category marker */ } + +public class A { + @Test + public void a() { + fail(); + } + + @Category(SlowTests.class) + @Test + public void b() { + } +} + +@Category({SlowTests.class, FastTests.class}) +public class B { + @Test + public void c() { + + } +} + +@RunWith(Categories.class) +@IncludeCategory(SlowTests.class) +@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite +public class SlowTestSuite { + // Will run A.b and B.c, but not A.a +} + +@RunWith(Categories.class) +@IncludeCategory(SlowTests.class) +@ExcludeCategory(FastTests.class) +@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite +public class SlowTestSuite { + // Will run A.b, but not A.a or B.c +} +</code></pre> + +<h3>Bug fixes</h3> + +<ul> +<li>github#16: thread safety of Result counting</li> +</ul> diff --git a/junit4/doc/ReleaseNotes4.8.txt b/junit4/doc/ReleaseNotes4.8.txt new file mode 100644 index 0000000..4a30db6 --- /dev/null +++ b/junit4/doc/ReleaseNotes4.8.txt @@ -0,0 +1,56 @@ +## Summary of Changes in version 4.8 ## + +### Categories ### + +From a given set of test classes, the `Categories` runner +runs only the classes and methods +that are annotated with either the category given with the `@IncludeCategory` +annotation, or a subtype of that category. Either classes or interfaces can be +used as categories. Subtyping works, so if you say `@IncludeCategory(SuperClass.class)`, +a test marked `@Category({SubClass.class})` will be run. + +You can also exclude categories by using the `@ExcludeCategory` annotation + +Example: + + public interface FastTests { /* category marker */ } + public interface SlowTests { /* category marker */ } + + public class A { + @Test + public void a() { + fail(); + } + + @Category(SlowTests.class) + @Test + public void b() { + } + } + + @Category({SlowTests.class, FastTests.class}) + public class B { + @Test + public void c() { + + } + } + + @RunWith(Categories.class) + @IncludeCategory(SlowTests.class) + @SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite + public class SlowTestSuite { + // Will run A.b and B.c, but not A.a + } + + @RunWith(Categories.class) + @IncludeCategory(SlowTests.class) + @ExcludeCategory(FastTests.class) + @SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite + public class SlowTestSuite { + // Will run A.b, but not A.a or B.c + } + +### Bug fixes ### + +- github#16: thread safety of Result counting
\ No newline at end of file diff --git a/junit4/doc/ReleaseNotes4.9.1.txt b/junit4/doc/ReleaseNotes4.9.1.txt new file mode 100644 index 0000000..eded783 --- /dev/null +++ b/junit4/doc/ReleaseNotes4.9.1.txt @@ -0,0 +1,14 @@ +## Summary of Changes in version 4.9.1 [unreleased!] ## + +### Theories ### + +The `Theories` runner does not anticipate theory parameters that have generic +types, as reported by github#64. Fixing this won't happen until `Theories` is +moved to junit-contrib. In anticipation of this, 4.9.1 adds some of the +necessary machinery to the runner classes, and deprecates a method that only +the `Theories` runner uses, `FrameworkMethod`#producesType(). +The Common Public License that JUnit is released under is now included +in the source repository. + +Thanks to `@pholser` for identifying a potential resolution for github#64 +and initiating work on it. diff --git a/junit4/doc/ReleaseNotes4.9.html b/junit4/doc/ReleaseNotes4.9.html new file mode 100644 index 0000000..3692102 --- /dev/null +++ b/junit4/doc/ReleaseNotes4.9.html @@ -0,0 +1,96 @@ +<h2>Summary of Changes in version 4.9, final</h2> + +<p>Release theme: Test-class and suite level Rules.</p> + +<h3>ClassRule</h3> + +<p>The <code>ClassRule</code> annotation extends the idea of method-level Rules, +adding static fields that can affect the operation of a whole class. Any +subclass of <code>ParentRunner</code>, including the standard <code>BlockJUnit4ClassRunner</code> +and <code>Suite</code> classes, will support <code>ClassRule</code>s.</p> + +<p>For example, here is a test suite that connects to a server once before +all the test classes run, and disconnects after they are finished:</p> + +<pre><code>@RunWith(Suite.class) +@SuiteClasses({A.class, B.class, C.class}) +public class UsesExternalResource { + public static Server myServer= new Server(); + + @ClassRule + public static ExternalResource resource= new ExternalResource() { + @Override + protected void before() throws Throwable { + myServer.connect(); + }; + + @Override + protected void after() { + myServer.disconnect(); + }; + }; +} +</code></pre> + +<h3>TestRule</h3> + +<p>In JUnit 4.9, fields that can be annotated with either <code>@Rule</code> or <code>@ClassRule</code> +should be of type <code>TestRule</code>. The old <code>MethodRule</code> type, which only made sense +for method-level rules, will still work, but is deprecated.</p> + +<p>Most built-in Rules have been moved to the new type already, in a way that +should be transparent to most users. <code>TestWatchman</code> has been deprecated, +and replaced by <code>TestWatcher</code>, which has the same functionality, but implements +the new type.</p> + +<h3>Maven support</h3> + +<p>Maven bundles have, in the past, been uploaded by kind volunteers. Starting +with this release, the JUnit team is attempting to perform this task ourselves.</p> + +<h3>LICENSE checked in</h3> + +<p>The Common Public License that JUnit is released under is now included +in the source repository.</p> + +<h3>Bug fixes</h3> + +<ul> +<li>github#98: assumeTrue() does not work with expected exceptions</li> +<li><p>github#74: Categories + Parameterized</p> + +<p>In JUnit 4.8.2, the Categories runner would fail to run correctly +if any contained test class had a custom Runner with a structure +significantly different from the built-in Runner. With this fix, +such classes can be assigned one or more categories at the class level, +and will be run correctly. Trying to assign categories to methods within +such a class will flag an error.</p></li> +<li><p>github#38: ParentRunner filters more than once</p> + +<p>Thanks to <code>@reinholdfuereder</code></p></li> +<li><p>github#248: protected BlockJUnit4ClassRunner#rules method removed from 4.8.2</p></li> +<li>github#187: Accidental dependency on Java 6</li> +</ul> + +<p>Thanks to <code>@kcooney</code> for:</p> + +<ul> +<li>github#163: Bad comparison failure message when using assertEquals(String, String)</li> +<li>github#227: ParentRunner now assumes that getChildren() returns a modifiable list</li> +</ul> + +<h3>Minor changes</h3> + +<ul> +<li>Backed out unused folder "experimental-use-of-antunit", replaced by +bash-based script at build_tests.sh</li> +<li>Various Javadoc fixes</li> +</ul> + +<p>Thanks to <code>@kcooney</code> for:</p> + +<ul> +<li>Made MultipleFailureException public, to assist extension writers.</li> +<li>github#240: Add "test" target to build.xml, for faster ant-driven testing.</li> +<li>github#247: Give InitializationError a useful message</li> +</ul> diff --git a/junit4/doc/ReleaseNotes4.9.txt b/junit4/doc/ReleaseNotes4.9.txt new file mode 100644 index 0000000..8b2a63d --- /dev/null +++ b/junit4/doc/ReleaseNotes4.9.txt @@ -0,0 +1,89 @@ +## Summary of Changes in version 4.9, final ## + +Release theme: Test-class and suite level Rules. + +### ClassRule ### + +The `ClassRule` annotation extends the idea of method-level Rules, +adding static fields that can affect the operation of a whole class. Any +subclass of `ParentRunner`, including the standard `BlockJUnit4ClassRunner` +and `Suite` classes, will support `ClassRule`s. + +For example, here is a test suite that connects to a server once before +all the test classes run, and disconnects after they are finished: + + @RunWith(Suite.class) + @SuiteClasses({A.class, B.class, C.class}) + public class UsesExternalResource { + public static Server myServer= new Server(); + + @ClassRule + public static ExternalResource resource= new ExternalResource() { + @Override + protected void before() throws Throwable { + myServer.connect(); + }; + + @Override + protected void after() { + myServer.disconnect(); + }; + }; + } + +### TestRule ### + +In JUnit 4.9, fields that can be annotated with either `@Rule` or `@ClassRule` +should be of type `TestRule`. The old `MethodRule` type, which only made sense +for method-level rules, will still work, but is deprecated. + +Most built-in Rules have been moved to the new type already, in a way that +should be transparent to most users. `TestWatchman` has been deprecated, +and replaced by `TestWatcher`, which has the same functionality, but implements +the new type. + +### Maven support ### + +Maven bundles have, in the past, been uploaded by kind volunteers. Starting +with this release, the JUnit team is attempting to perform this task ourselves. + +### LICENSE checked in ### + +The Common Public License that JUnit is released under is now included +in the source repository. + +### Bug fixes ### + +- github#98: assumeTrue() does not work with expected exceptions +- github#74: Categories + Parameterized + + In JUnit 4.8.2, the Categories runner would fail to run correctly + if any contained test class had a custom Runner with a structure + significantly different from the built-in Runner. With this fix, + such classes can be assigned one or more categories at the class level, + and will be run correctly. Trying to assign categories to methods within + such a class will flag an error. + +- github#38: ParentRunner filters more than once + + Thanks to `@reinholdfuereder` + +- github#248: protected BlockJUnit4ClassRunner#rules method removed from 4.8.2 +- github#187: Accidental dependency on Java 6 + +Thanks to `@kcooney` for: + +- github#163: Bad comparison failure message when using assertEquals(String, String) +- github#227: ParentRunner now assumes that getChildren() returns a modifiable list + +### Minor changes ### + +- Backed out unused folder "experimental-use-of-antunit", replaced by + bash-based script at build_tests.sh +- Various Javadoc fixes + +Thanks to `@kcooney` for: + +- Made MultipleFailureException public, to assist extension writers. +- github#240: Add "test" target to build.xml, for faster ant-driven testing. +- github#247: Give InitializationError a useful message diff --git a/junit4/doc/building-junit.txt b/junit4/doc/building-junit.txt new file mode 100644 index 0000000..e785b05 --- /dev/null +++ b/junit4/doc/building-junit.txt @@ -0,0 +1,19 @@ +Steps to build junit: + +- Must be manual + - Write release notes + - Update version in build.xml +- Not too tedious: + - Push to github (dsaff _and_ KentBeck) + - Run the ant zip task + - Upload stuff to github (including tag) + - Push to maven + - ant -lib build/lib stage.maven + - Promote +- Tedious: + - Update SourceForge if major release + - Update javadocs on github site (and "latest" link) + - Update javadocs on junit.org + - Put release notes on github. + - Announce on blog, user list, dev list, announce list, junit.org, twitter +- Profit! diff --git a/junit4/doc/cookbook/cookbook.htm b/junit4/doc/cookbook/cookbook.htm new file mode 100644 index 0000000..2cf8eec --- /dev/null +++ b/junit4/doc/cookbook/cookbook.htm @@ -0,0 +1,143 @@ +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> + <meta name="Author" content="Erich Gamma"> + <title>JUnit Cookbook</title> +</head> +<body> + +<h1> +<font color="#33FF33">J</font><font color="#CC0000">U</font>nit Cookbook</h1> + +<p> +Kent Beck, Erich Gamma</p> + +<hr WIDTH="100%"> +<br>Here is a short cookbook showing you the steps you can follow in writing +and organizing your own tests using JUnit. +<h2> +Simple Test Case</h2> +How do you write testing code? +<p>The simplest way is as an expression in a debugger. You can change debug +expressions without recompiling, and you can wait to decide what to write +until you have seen the running objects. You can also write test expressions +as statements which print to the standard output stream. Both styles of +tests are limited because they require human judgment to analyze their +results. Also, they don't compose nicely- you can only execute one debug +expression at a time and a program with too many print statements causes +the dreaded "Scroll Blindness". +<p>JUnit tests do not require human judgment to interpret, and it is easy +to run many of them at the same time. When you need to test something, +here is what you do: +<ol> +<li> +Annotate a method with @org.junit.Test + +<li> +When you want to check a value, import org.junit.Assert.* statically, call <tt>assertTrue</tt>() and pass a boolean +that is true if the test succeeds</li> +</ol> +For example, to test that the sum of two Moneys with the same currency +contains a value which is the sum of the values of the two Moneys, write: +<blockquote> +<pre><tt>@Test public void simpleAdd() { + Money m12CHF= new Money(12, "CHF"); + Money m14CHF= new Money(14, "CHF"); + Money expected= new Money(26, "CHF"); + Money result= m12CHF.add(m14CHF); + assertTrue(expected.equals(result)); +}</tt></pre> +</blockquote> +If you want to write a test similar to one you have already written, write +a Fixture instead. +<h2> +Fixture</h2> +What if you have two or more tests that operate on the same or similar +sets of objects? +<p>Tests need to run against the background of a known set of objects. +This set of objects is called a test fixture. When you are writing tests +you will often find that you spend more time writing the code to set up +the fixture than you do in actually testing values. +<p>To some extent, you can make writing the fixture code easier by paying +careful attention to the constructors you write. However, a much bigger +savings comes from sharing fixture code. Often, you will be able to use +the same fixture for several different tests. Each case will send slightly +different messages or parameters to the fixture and will check for different +results. +<p>When you have a common fixture, here is what you do: +<ol> + +<li> +Add a field for each part of the fixture</li> + +<li> +Annotate a method with @org.junit.Before +and initialize the variables in that method</li> + +<li> +Annotate a method with @org.junit.After +to release any permanent resources you allocated in setUp</li> +</ol> +For example, to write several test cases that want to work with different +combinations of 12 Swiss Francs, 14 Swiss Francs, and 28 US Dollars, first +create a fixture: +<pre><tt>public class MoneyTest { + private Money f12CHF; + private Money f14CHF; + private Money f28USD; + + @Before public void setUp() { + f12CHF= new Money(12, "CHF"); + f14CHF= new Money(14, "CHF"); + f28USD= new Money(28, "USD"); + } +}</tt></pre> +Once you have the Fixture in place, you can write as many Test Cases as +you'd like. Add as many test methods (annotated with @Test) as you'd like. +<h2>Running Tests</h2> +How do you run your tests and collect their results? +<p>Once you have tests, you'll want to run them. JUnit provides tools +to define the suite to be run and to display its results. To run tests and see the +results on the console, run this from a Java program: +<blockquote> +<pre> +org.junit.runner.JUnitCore.runClasses(TestClass1.class, ...); +</pre> +</blockquote> +or this from the command line, with both your test class and junit on the classpath: +<blockquote> +<pre> +java org.junit.runner.JUnitCore TestClass1.class [...other test classes...] +</pre> +</blockquote> + +You make your JUnit 4 test classes accessible to a TestRunner designed to work with earlier versions of JUnit, +declare a static method <i>suite</i> +that returns a test. +<blockquote> +<pre><tt>public static junit.framework.Test suite() { + return new JUnit4TestAdapter(Example.class); +}</tt></pre> +</blockquote> +<h2> +Expected Exceptions</h2> +How do you verify that code throws exceptions as expected? +<p>Verifying that code completes normally is only part of programming. Making sure the code +behaves as expected in exceptional situations is part of the craft of programming too. For example: +<blockquote> +<pre><tt>new ArrayList<Object>().get(0); +</tt></pre> +</blockquote> +This code should throw an IndexOutOfBoundsException. The @Test annotation has an optional parameter "expected" +that takes as values subclasses of Throwable. If we wanted to verify that ArrayList throws the correct exception, +we would write: +<blockquote> +<pre><tt>@Test(expected= IndexOutOfBoundsException.class) public void empty() { + new ArrayList<Object>().get(0); +}</tt></pre> +</blockquote> +<hr WIDTH="100%"> +</body> +</html> diff --git a/junit4/doc/cookbook/logo.gif b/junit4/doc/cookbook/logo.gif Binary files differnew file mode 100644 index 0000000..d0e1547 --- /dev/null +++ b/junit4/doc/cookbook/logo.gif diff --git a/junit4/doc/cookstour/Image1.gif b/junit4/doc/cookstour/Image1.gif Binary files differnew file mode 100644 index 0000000..398d4cc --- /dev/null +++ b/junit4/doc/cookstour/Image1.gif diff --git a/junit4/doc/cookstour/Image2.gif b/junit4/doc/cookstour/Image2.gif Binary files differnew file mode 100644 index 0000000..072149f --- /dev/null +++ b/junit4/doc/cookstour/Image2.gif diff --git a/junit4/doc/cookstour/Image3.gif b/junit4/doc/cookstour/Image3.gif Binary files differnew file mode 100644 index 0000000..dbf6649 --- /dev/null +++ b/junit4/doc/cookstour/Image3.gif diff --git a/junit4/doc/cookstour/Image4.gif b/junit4/doc/cookstour/Image4.gif Binary files differnew file mode 100644 index 0000000..b0b1f2b --- /dev/null +++ b/junit4/doc/cookstour/Image4.gif diff --git a/junit4/doc/cookstour/Image5.gif b/junit4/doc/cookstour/Image5.gif Binary files differnew file mode 100644 index 0000000..5393c63 --- /dev/null +++ b/junit4/doc/cookstour/Image5.gif diff --git a/junit4/doc/cookstour/Image6.gif b/junit4/doc/cookstour/Image6.gif Binary files differnew file mode 100644 index 0000000..6804925 --- /dev/null +++ b/junit4/doc/cookstour/Image6.gif diff --git a/junit4/doc/cookstour/Image7.gif b/junit4/doc/cookstour/Image7.gif Binary files differnew file mode 100644 index 0000000..6af54a6 --- /dev/null +++ b/junit4/doc/cookstour/Image7.gif diff --git a/junit4/doc/cookstour/cookstour.htm b/junit4/doc/cookstour/cookstour.htm new file mode 100644 index 0000000..597dcd8 --- /dev/null +++ b/junit4/doc/cookstour/cookstour.htm @@ -0,0 +1,668 @@ +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <meta name="Generator" content="Microsoft Word 97"> + <meta name="GENERATOR" content="Mozilla/4.5 [en] (Win95; I) [Netscape]"> + <meta name="Author" content="ERICH GAMMA"> + <title>JUnit: A Cook’s Tour</title> +</head> +<body> + +<h1> +<font color="#33FF33">J</font><font color="#CC0000">U</font>nit A Cook's +Tour</h1> +<br>Note: this article is based on JUnit 3.8.x. +<hr WIDTH="100%"> +<p><b><font face="Arial"><font size=+1>1. Introduction</font></font></b> +<p><font size=-1>In an earlier article (see Test Infected: Programmers +Love Writing Tests, Java Report, July 1998, Volume 3, Number 7), we described +how to use a simple framework to write repeatable tests. In this article, +we will take a peek under the covers and show you how the framework itself +is constructed.</font> +<p><font size=-1>We carefully studied the JUnit framework and reflected +on how we constructed it. We found lessons at many different levels. In +this article we will try communicate them all at once, a hopeless task, +but at least we will do it in the context of showing you the design and +construction of a piece of software with proven value.</font> +<p><font size=-1>We open with a discussion of the goals of the framework. +The goals will reappear in many small details during the presentation of +the framework itself. Following this, we present the design and implementation +of the framework. The design will be described in terms of patterns (surprise, +surprise), the implementation as a literate program. We conclude with a +few choice thoughts about framework development.</font> +<p><b><font face="Arial"><font size=+1>2. Goals</font></font></b> +<p><font size=-1>What are the goals of JUnit?</font> +<p><font size=-1>First, we have to get back to the assumptions of development. +If a program feature lacks an automated test, we assume it doesn’t work. +This seems much safer than the prevailing assumption, that if a developer +assures us a program feature works, then it works now and forever.</font> +<p><font size=-1>From this perspective, developers aren’t done when they +write and debug the code, they must also write tests that demonstrate that +the program works. However, everybody is too busy, they have too much to +do, they don’t have enough time, to screw around with testing. I have too +much code to write already, how am I supposed write test code, too? Answer +me that, Mr. Hard-case Project Manager.</font> +<p><font size=-1>So, the number one goal is to write a framework within +which we have some glimmer of hope that developers will actually write +tests. The framework has to use familiar tools, so there is little new +to learn. It has to require no more work than absolutely necessary to write +a new test. It has to eliminate duplicated effort.</font> +<p><font size=-1>If this was all tests had to do, you would be done just +by writing expressions in a debugger. However, this isn’t sufficient for +testing. Telling me that your program works now doesn’t help me, because +it doesn’t assure me that your program will work one minute from now after +I integrate, and it doesn’t assure me that your program will still work +in five years, when you are long gone.</font> +<p><font size=-1>So, the second goal of testing is creating tests that +retain their value over time. Someone other than the original author has +to be able to execute the tests and interpret the results. It should be +possible to combine tests from various authors and run them together without +fear of interference.</font> +<p><font size=-1>Finally, it has to be possible to leverage existing tests +to create new ones. Creating a setup or fixture is expensive and a framework +has to enable reusing fixtures to run different tests. Oh, is that all?</font> +<p><b><font face="Arial"><font size=+1>3. The Design of JUnit</font></font></b> +<p><font size=-1>The design of JUnit will be presented in a style first +used in (see "Patterns Generate Architectures", Kent Beck and Ralph Johnson, +ECOOP 94). The idea is to explain the design of a system by starting with +nothing and applying patterns, one after another, until you have the architecture +of the system. We will present the architectural problem to be solved, +summarize the pattern that solves it, and then show how the pattern was +applied to JUnit.</font> +<p><b><i><font face="Arial">3.1 Getting started- TestCase</font></i></b> +<p><font size=-1>First we have to make an object to represent our basic +concept, the TestCase. Developers often have tests cases in mind, but they +realize them in many different ways-</font> +<ul> +<li> +<font size=-1>print statements,</font></li> + +<li> +<font size=-1>debugger expressions,</font></li> + +<li> +<font size=-1>test scripts.</font></li> +</ul> +<font size=-1>If we want to make manipulating tests easy, we have to make +them objects. This takes a test that was only implicit in the developer’s +mind and makes it concrete, supporting our goal of creating tests that +retain their value over time. At the same time, object developers are used +to, well, developing with objects, so the decision to make tests into objects +supports our goal of making test writing more inviting (or at least less +imposing).</font> +<p><font size=-1>The Command pattern (see Gamma, E., et al. Design Patterns: +Elements of Reusable Object-Oriented Software, Addison-Wesley, Reading, +MA, 1995) fits our needs quite nicely. Quoting from the intent, "Encapsulate +a request as an object, thereby letting you… queue or log requests…" Command +tells us to create an object for an operation and give it a method "execute". +Here is the code for the class definition of TestCase:</font> +<dir> +<dir><font face="Arial"><font size=-2>public abstract class <b>TestCase</b> +implements Test {</font></font> +<br><font face="Arial"><font size=-2> …</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>Because we expect this class to be reused through inheritance, +we declare it "public abstract". For now, ignore the fact that it implements +the Test interface. For the purposes of our current design, you can think +of TestCase as a lone class.</font> +<p><font size=-1>Every TestCase is created with a name, so if a test fails, +you can identify which test failed.</font> +<dir> +<dir><font face="Arial"><font size=-2>public abstract class <b>TestCase</b> +implements Test {</font></font> +<br><font face="Arial"><font size=-2> private final String +fName;</font></font> +<p><font face="Arial"><font size=-2> public <b>TestCase</b>(String +name) {</font></font> +<br><font face="Arial"><font size=-2> +fName= name;</font></font> +<br><font face="Arial"><font size=-2> }</font></font> +<p><font face="Arial"><font size=-2> public abstract +void <b>run</b>();</font></font> +<br><font face="Arial"><font size=-2> +…</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>To illustrate the evolution of JUnit, we use diagrams that +show snapshots of the architecture. The notation we use is simple. It annotates +classes with shaded boxes containing the associated pattern. When the role +of the class in the pattern is obvious then only the pattern name is shown. +If the role isn’t clear then the shaded box is augmented by the name of +the participant this class corresponds to. This notation minimizes the +clutter in diagrams and was first shown in (see Gamma, E., Applying Design +Patterns in Java, in Java Gems, SIGS Reference Library, 1997) Figure 1 +shows this notation applied to TestCase. Since we are dealing with a single +class and there can be no ambiguities just the pattern name is shown.</font> +<center> +<p><img SRC="Image1.gif" height=92 width=238> +<p><font size=-1><b>Figure 1</b> TestCase applies Command</font></center> + +<p><b><i><font face="Arial">3.2 Blanks to fill in- run()</font></i></b> +<p><font size=-1>The next problem to solve is giving the developer a convenient +"place" to put their fixture code and their test code. The declaration +of TestCase as abstract says that the developer is expected to reuse TestCase +by subclassing. However, if all we could do was provide a superclass with +one variable and no behavior, we wouldn’t be doing much to satisfy our +first goal, making tests easier to write.</font> +<p><font size=-1>Fortunately, there is a common structure to all tests- +they set up a test fixture, run some code against the fixture, check some +results, and then clean up the fixture. This means that each test will +run with a fresh fixture and the results of one test can’t influence the +result of another. This supports the goal of maximizing the value of the +tests.</font> +<p><font size=-1>Template Method addresses our problem quite nicely. Quoting +from the intent, "Define the skeleton of an algorithm in an operation, +deferring some steps to subclasses. Template Method lets subclasses redefine +certain steps of an algorithm without changing the algorithm’s structure." +This is exactly right. We want the developer to be able to separately consider +how to write the fixture (set up and tear down) code and how to write the +testing code. The execution of this sequence, however, will remain the +same for all tests, no matter how the fixture code is written or how the +testing code is written.</font> +<p><font size=-1>Here is the template method:</font> +<dir> +<dir><font face="Arial"><font size=-2>public void <b>run</b>() {</font></font> +<br><font face="Arial"><font size=-2> setUp();</font></font> +<br><font face="Arial"><font size=-2> runTest();</font></font> +<br><font face="Arial"><font size=-2> tearDown();</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>The default implementations of these methods do nothing:</font> +<dir> +<dir><font face="Arial"><font size=-2>protected void <b>runTest</b>() {</font></font> +<br><font face="Arial"><font size=-2>}</font></font> +<p><font face="Arial"><font size=-2>protected void <b>setUp</b>() {</font></font> +<br><font face="Arial"><font size=-2>}</font></font> +<p><font face="Arial"><font size=-2>protected void <b>tearDown</b>() {</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>Since setUp and tearDown are intended to be overridden but +will be called by the framework we declare them as protected. The second +snapshot of our tour is depicted in Figure 2.</font> +<center> +<p><img SRC="Image2.gif" height=142 width=270> +<p><font size=-1><b>Figure 2</b> TestCase.run() applies Template Method</font></center> + +<p><b><i><font face="Arial">3.3 Reporting results- TestResult</font></i></b> +<p><font size=-1>If a TestCase runs in a forest, does anyone care about +the result? Sure- you run tests to make sure they run. After the test has +run, you want a record, a summary of what did and didn’t work.</font> +<p><font size=-1>If tests had equal chances of succeeding or failing, or +if we only ever ran one test, we could just set a flag in the TestCase +object and go look at the flag when the test completed. However, tests +are (intended to be) highly asymmetric- they usually work. Therefore, we +only want to record the failures and a highly condensed summary of the +successes.</font> +<p><font size=-1>The Smalltalk Best Practice Patterns (see Beck, K. Smalltalk +Best Practice Patterns, Prentice Hall, 1996) has a pattern that is applicable. +It is called <i>Collecting Parameter</i>. It suggests that when you need +to collect results over several methods, you should add a parameter to +the method and pass an object that will collect the results for you. We +create a new object, TestResult, to collect the results of running tests.</font> +<dir> +<dir><font face="Arial"><font size=-2>public class <b>TestResult</b> extends +Object {</font></font> +<br><font face="Arial"><font size=-2> protected int fRunTests;</font></font> +<p><font face="Arial"><font size=-2> public <b>TestResult</b>() +{</font></font> +<br><font face="Arial"><font size=-2> +fRunTests= 0;</font></font> +<br><font face="Arial"><font size=-2> }</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>This simple version of TestResult only counts the number +of tests run. To use it, we have to add a parameter to the TestCase.run() +method and notify the TestResult that the test is running:</font> +<dir> +<dir><font face="Arial"><font size=-2>public void <b>run</b>(TestResult +result) {</font></font> +<br><font face="Arial"><font size=-2> result.startTest(this);</font></font> +<br><font face="Arial"><font size=-2> setUp();</font></font> +<br><font face="Arial"><font size=-2> runTest();</font></font> +<br><font face="Arial"><font size=-2> tearDown();</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>And the TestResult has to keep track of the number of tests +run:</font> +<dir> +<dir><font face="Arial"><font size=-2>public synchronized void <b>startTest</b>(Test +test) {</font></font> +<br><font face="Arial"><font size=-2> fRunTests++;</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>We declare the TestResult method startTest as synchronized +so that a single TestResult can collect the results safely when the tests +are run in different threads. Finally, we want to retain the simple external +interface of TestCase, so we create a no-parameter version of run() that +creates its own TestResult:</font> +<dir> +<dir><font face="Arial"><font size=-2>public TestResult <b>run</b>() {</font></font> +<br><font face="Arial"><font size=-2> TestResult result= +createResult();</font></font> +<br><font face="Arial"><font size=-2> run(result);</font></font> +<br><font face="Arial"><font size=-2> return result;</font></font> +<br><font face="Arial"><font size=-2>}</font></font> +<p><font face="Arial"><font size=-2>protected TestResult <b>createResult</b>() +{</font></font> +<br><font face="Arial"><font size=-2> return new TestResult();</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>Figure 3 shows our next design snapshot.</font> +<center> +<p><img SRC="Image3.gif" height=149 width=325> +<p><font size=-1>Figure 3: TestResult applies Collecting Parameter</font></center> + +<p><font size=-1>If tests always ran correctly, then we wouldn’t have to +write them. Tests are interesting when they fail, especially if we didn’t +expect them to fail. What’s more, tests can fail in ways that we expect, +for example by computing an incorrect result, or they can fail in more +spectacular ways, for example by writing outside the bounds of an array. +No matter how the test fails we want to execute the following tests.</font> +<p><font size=-1>JUnit distinguishes between <i>failures</i> and <i>errors</i>. +The possibility of a failure is anticipated and checked for with assertions. +Errors are unanticipated problems like an ArrayIndexOutOfBoundsException. +Failures are signaled with an AssertionFailedError error. To distinguish +an unanticipated error from a failure, failures are caught in an extra +catch clause (1). The second clause (2) catches all other exceptions and +ensures that our test run continues..</font> +<dir> +<dir><font face="Arial"><font size=-2>public void <b>run</b>(TestResult +result) {</font></font> +<br><font face="Arial"><font size=-2> result.startTest(this);</font></font> +<br><font face="Arial"><font size=-2> setUp();</font></font> +<br><font face="Arial"><font size=-2> try {</font></font> +<br><font face="Arial"><font size=-2> +runTest();</font></font> +<br><font face="Arial"><font size=-2> }</font></font> +<br><font face="Arial"><font size=-2> catch (AssertionFailedError +e) { //1</font></font> +<br><font face="Arial"><font size=-2> +result.addFailure(this, e);</font></font> +<br><font face="Arial"><font size=-2> }</font></font> +<p><font face="Arial"><font size=-2> catch (Throwable +e) { // 2</font></font> +<br><font face="Arial"><font size=-2> +result.addError(this, e);</font></font> +<br><font face="Arial"><font size=-2> }</font></font> +<br><font face="Arial"><font size=-2> finally {</font></font> +<br><font face="Arial"><font size=-2> +tearDown();</font></font> +<br><font face="Arial"><font size=-2> }</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>An AssertionFailedError is triggered by the assert methods +provided by TestCase. JUnit provides a set of assert methods for different +purposes. Here is the simplest one:</font> +<dir> +<dir><font face="Arial"><font size=-2>protected void <b>assertTrue</b>(boolean +condition) {</font></font> +<br><font face="Arial"><font size=-2> if (!condition)</font></font> +<br><font face="Arial"><font size=-2> +throw new AssertionFailedError();</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>The AssertionFailedError is not meant to be caught by the +client (a testing method inside a TestCase) but inside the Template Method +TestCase.run(). We therefore derive AssertionFailedError from Error.</font> +<dir> +<dir><font face="Arial"><font size=-2>public class <b>AssertionFailedError</b> +extends Error {</font></font> +<br><font face="Arial"><font size=-2> public AssertionFailedError +() {}</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>The methods to collect the errors in TestResult are shown +below:</font> +<dir> +<dir><font face="Arial"><font size=-2>public synchronized void <b>addError</b>(Test +test, Throwable t) {</font></font> +<br><font face="Arial"><font size=-2> fErrors.addElement(new +TestFailure(test, t));</font></font> +<br><font face="Arial"><font size=-2>}</font></font> +<p><font face="Arial"><font size=-2>public synchronized void <b>addFailure</b>(Test +test, Throwable t) {</font></font> +<br><font face="Arial"><font size=-2> fFailures.addElement(new +TestFailure(test, t));</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>TestFailure is a little framework internal helper class to +bind together the failed test and the signaled exception for later reporting.</font> +<dir> +<dir><font face="Arial"><font size=-2>public class <b>TestFailure</b> extends +Object {</font></font> +<br><font face="Arial"><font size=-2> protected Test +fFailedTest;</font></font> +<br><font face="Arial"><font size=-2> protected Throwable +fThrownException;</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>The canonical form of collecting parameter requires us to +pass the collecting parameter to each method. If we followed this advice, +each of the testing methods would require a parameter for the TestResult. +This results in a "pollution" of these method signatures. As a benevolent +side effect of using exceptions to signal failures we can avoid this signature +pollution. A test case method, or a helper method called from it, can throw +an exception without having to know about the TestResult. As a refresher +here is a sample test method from our MoneyTest suite. It illustrates how +a testing method doesn’t have to know anything about a TestResult:</font> +<dir> +<dir><font face="Arial"><font size=-2>public void <b>testMoneyEquals</b>() +{</font></font> +<br><font face="Arial"><font size=-2> assertTrue(!f12CHF.equals(null));</font></font> +<br><font face="Arial"><font size=-2> assertEquals(f12CHF, +f12CHF);</font></font> +<br><font face="Arial"><font size=-2> assertEquals(f12CHF, +new Money(12, "CHF"));</font></font> +<br><font face="Arial"><font size=-2> assertTrue(!f12CHF.equals(f14CHF));</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>JUnit comes with different implementations of TestResult. +The default implementation counts the number of failures and errors and +collects the results. TextTestResult collects the results and presents +them in a textual form. Finally, UITestResult is used by the graphical +version of the JUnit Test Runner to update the graphical test status.</font> +<p><font size=-1>TestResult is an extension point of the framework. Clients +can define their own custom TestResult classes, for example, an HTMLTestResult +reports the results as an HTML document.</font> +<p><b><i><font face="Arial">3.4 No stupid subclasses - TestCase again</font></i></b> +<p><font size=-1>We have applied Command to represent a test. Command relies +on a single method like execute() (called run() in TestCase) to invoke +it. This simple interface allows us to invoke different implementations +of a command through the same interface.</font> +<p><font size=-1>We need an interface to generically run our tests. However, +all test cases are implemented as different methods in the same class. +This avoids the unnecessary proliferation of classes. A given test case +class may implement many different methods, each defining a single test +case. Each test case has a descriptive name like testMoneyEquals or testMoneyAdd. +The test cases don’t conform to a simple command interface. Different instances +of the same Command class need to be invoked with different methods. Therefore +our next problem is make all the test cases look the same from the point +of view of the invoker of the test.</font> +<p><font size=-1>Reviewing the problems addressed by available design patterns, +the Adapter pattern springs to mind. Adapter has the following intent "Convert +the interface of a class into another interface clients expect". This sounds +like a good match. Adapter tells us different ways to do this. One of them +is a class adapter, which uses subclassing to adapt the interface. For +example, to adapt testMoneyEquals to runTest we implement a subclass of +MoneyTest and override runTest to invoke testMoneyEquals.</font> +<dir> +<dir><font face="Arial"><font size=-2>public class <b>TestMoneyEquals</b> +extends MoneyTest {</font></font> +<br><font face="Arial"><font size=-2> public TestMoneyEquals() +{ super("testMoneyEquals"); }</font></font> +<br><font face="Arial"><font size=-2> protected void +runTest () { testMoneyEquals(); }</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>The use of subclassing requires us to implement a subclass +for each test case. This puts an additional burden on the tester. This +is against the JUnit goal that the framework should make it as simple as +possible to add a test case. In addition, creating a subclass for each +testing method results in class bloat. Many classes with only a single +method are not worth their costs and it will be difficult to come up with +meaningful names.</font> +<p><font size=-1>Java provides anonymous inner classes which provide an +interesting Java-specific solution to the class naming problem. With anonymous +inner classes we can create an Adapter without having to invent a class +name:</font> +<dir> +<dir><font face="Arial"><font size=-2>TestCase test= new MoneyTest("testMoneyEquals +") {</font></font> +<br><font face="Arial"><font size=-2> protected void +runTest() { testMoneyEquals(); }</font></font> +<br><font face="Arial"><font size=-2>};</font></font></dir> +</dir> +<font size=-1>This is much more convenient than full subclassing. It preserves +compile-time type checking at the cost of some burden on the developer. +Smalltalk Best Practice Patterns describes another solution for the problem +of different instances behaving differently under the common heading of<i> +pluggable behavior</i>. The idea is to use a single class which can be +parameterized to perform different logic without requiring subclassing.</font> +<p><font size=-1>The simplest form of pluggable behavior is the <i>Pluggable +Selector</i>. Pluggable Selector stores a Smalltalk method selector in +an instance variable. This idea is not limited to Smalltalk. It is also +applicable to Java. In Java there is no notion of a method selector. However, +the Java reflection API allows us to invoke a method from a string representing +the method’s name. We can use this feature to implement a pluggable selector +in Java. As an aside, we usually don’t use reflection in ordinary application +code. In our case we are dealing with an infrastructure framework and it +is therefore OK to wear the reflection hat.</font> +<p><font size=-1>JUnit offers the client the choice of using pluggable +selector or implementing an anonymous adapter class as shown above. To +do so, we provide the pluggable selector as the default implementation +of the runTest method. In this case the name of the test case has to correspond +to the name of a test method. We use reflection to invoke the method as +shown below. First we look up the Method object. Once we have the method +object we can invoke it and pass its arguments. Since our test methods +take no arguments we can pass an empty argument array:</font> +<dir> +<dir><font face="Arial"><font size=-2>protected void <b>runTest</b>() throws +Throwable {</font></font> +<br><font face="Arial"><font size=-2> Method runMethod= +null;</font></font> +<br><font face="Arial"><font size=-2> try {</font></font> +<br><font face="Arial"><font size=-2> +runMethod= getClass().getMethod(fName, new Class[0]);</font></font> +<br><font face="Arial"><font size=-2> } catch (NoSuchMethodException +e) {</font></font> +<br><font face="Arial"><font size=-2> +assertTrue("Method \""+fName+"\" not found", false);</font></font> +<br><font face="Arial"><font size=-2> }</font></font> +<br><font face="Arial"><font size=-2> try {</font></font> +<br><font face="Arial"><font size=-2> +runMethod.invoke(this, new Class[0]);</font></font> +<br><font face="Arial"><font size=-2> }</font></font> +<br><font face="Arial"><font size=-2> // catch InvocationTargetException +and IllegalAccessException</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>The JDK 1.1 reflection API only allows us to find public +methods. For this reason you have to declare the test methods as public, +otherwise you will get a NoSuchMethodException.</font> +<p><font size=-1>Here is the next design snapshot, with Adapter and Pluggable +Selector added.</font> +<center> +<p><img SRC="Image4.gif" height=271 width=278> +<p><font size=-1>Figure 4: TestCase applies either Adapter with an anonymous +inner class or Pluggable Selector</font></center> + +<p><b><i><font face="Arial">3.5 Don’t care about one or many - TestSuite</font></i></b> +<p><font size=-1>To get confidence in the state of a system we need to +run many tests. Up to this point JUnit can run a single test case and report +the result in a TestResult. Our next challenge is to extend it so that +it can run many different tests. This problem can be solved easily when +the invoker of the tests doesn’t have to care about whether it runs one +or many test cases. A popular pattern to pull out in such a situation is +Composite. To quote its intent "Compose objects into tree structures to +represent part-whole hierarchies. Composite lets clients treat individual +objects and compositions of objects uniformly." The point about part-whole +hierarchies is of interest here. We want to support suites of suites of +suites of tests.</font> +<p><font size=-1>Composite introduces the following participants:</font> +<ul> +<li> +<font size=-1>Component: declares the interface we want to use to interact +with our tests.</font></li> + +<li> +<font size=-1>Composite: implements this interface and maintains a collection +of tests.</font></li> + +<li> +<font size=-1>Leaf: represents a test case in a composition that conforms +to the Component interface.</font></li> +</ul> +<font size=-1>The pattern tells us to introduce an abstract class which +defines the common interface for single and composite objects. The primary +purpose of the class is to define an interface. When applying Composite +in Java we prefer to define an interface and not an abstract class. Using +an interface avoids committing JUnit to a specific base class for tests. +All that is required is that the tests conform to this interface. We therefore +tweak the pattern description and introduce a Test interface:</font> +<dir> +<dir><font face="Arial"><font size=-2>public interface <b>Test</b> {</font></font> +<br><font face="Arial"><font size=-2> public abstract +void run(TestResult result);</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>TestCase corresponds to a Leaf in Composite and implements +this interface as we have seen above.</font> +<p><font size=-1>Next, we introduce the Composite participant. We name +the class TestSuite. A TestSuite keeps its child tests in a Vector:</font> +<dir> +<dir><font face="Arial"><font size=-2>public class <b>TestSuite</b> implements +<b>Test</b> +{</font></font> +<br><font face="Arial"><font size=-2> private Vector +fTests= new Vector();</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>The run() method delegates to its children:</font> +<dir> +<dir><font face="Arial"><font size=-2>public void <b>run</b>(TestResult +result) {</font></font> +<br><font face="Arial"><font size=-2> for (Enumeration +e= fTests.elements(); e.hasMoreElements(); ) {</font></font> +<br><font face="Arial"><font size=-2> +Test test= (Test)e.nextElement();</font></font> +<br><font face="Arial"><font size=-2> +test.run(result);</font></font> +<br><font face="Arial"><font size=-2> }</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> + +<center><img SRC="Image5.gif" height=241 width=562> +<p><font size=-1>Figure 5: TestSuite applies Composite</font></center> + +<p><font size=-1>Finally, clients have to be able to add tests to a suite, +they can do so with the method addTest:</font> +<dir> +<dir><font face="Arial"><font size=-2>public void <b>addTest</b>(Test test) +{</font></font> +<br><font face="Arial"><font size=-2> fTests.addElement(test);</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>Notice how all of the above code only depends on the Test +interface. Since both TestCase and TestSuite conform to the Test interface +we can recursively compose suites of test suites. All developers can create +their own TestSuites. We can run them all by creating a TestSuite composed +of those suites.</font> +<p><font size=-1>Here is an example of creating a TestSuite:</font> +<dir> +<dir><font face="Arial"><font size=-2>public static Test <b>suite</b>() +{</font></font> +<br><font face="Arial"><font size=-2> TestSuite suite= +new TestSuite();</font></font> +<br><font face="Arial"><font size=-2> suite.addTest(new +MoneyTest("testMoneyEquals"));</font></font> +<br><font face="Arial"><font size=-2> suite.addTest(new +MoneyTest("testSimpleAdd"));</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>This works fine, but it requires us to add all the tests +to a suite manually. Early adopters of JUnit told us this was stupid. Whenever +you write a new test case you have to remember to add it to a static suite() +method, otherwise it will not be run. We added a convenience constructor +to TestSuite which takes the test case class as an argument. Its purpose +is to extract the test methods and create a suite containing them. The +test methods must follow the simple convention that they start with the +prefix "test" and take no arguments. The convenience constructor uses this +convention, constructing the test objects by using reflection to find the +testing methods. Using this constructor the above code is simplified to:</font> +<dir> +<dir><font face="Arial"><font size=-2>public static Test <b>suite</b>() +{</font></font> +<br><font face="Arial"><font size=-2> return new TestSuite(MoneyTest.class);</font></font> +<br><font face="Arial"><font size=-2>}</font></font></dir> +</dir> +<font size=-1>The original way is still useful when you want to run a subset +of the test cases only.</font> +<p><b><i><font face="Arial">3.6 Summary</font></i></b> +<p><font size=-1>We are at the end of our cook’s tour through JUnit. The +following figure shows the design of JUnit at a glance explained with patterns.</font> +<center> +<p><img SRC="Image6.gif" height=394 width=605> +<p><font size=-1>Figure 6: JUnit Patterns Summary</font></center> + +<p><font size=-1>Notice how TestCase, the central abstraction in the framework, +is involved in four patterns. Pictures of mature object designs show this +same "pattern density". The star of the design has a rich set of relationships +with the supporting players.</font> +<p><font size=-1>Here is another way of looking at all of the patterns +in JUnit. In this storyboard you see an abstract representation of the +effect of each of the patterns in turn. So, the Command pattern creates +the TestCase class, the Template Method pattern creates the run method, +and so on. (The notation of the storyboard is the notation of figure 6 +with all the text deleted).</font> +<center> +<p><img SRC="Image7.gif" height=231 width=792> +<p><font size=-1>Figure 7: JUnit Pattern Storyboard</font></center> + +<p><font size=-1>One point to notice about the storyboard is how the complexity +of the picture jumps when we apply Composite. This is pictorial corroboration +for our intuition that Composite is a powerful pattern, but that it "complicates +the picture." It should therefore be used with caution.</font> +<p><b><font face="Arial"><font size=+1>4. Conclusion</font></font></b> +<p><font size=-1>To conclude, let’s make some general observations:</font> +<ul> +<li> +<i><font size=-1>Patterns</font></i></li> + +<br><font size=-1>We found discussing the design in terms of patterns to +be invaluable, both as we were developing the framework and as we try to +explain it to others. You are now in a perfect position to judge whether +describing a framework with patterns is effective. If you liked the discussion +above, try the same style of presentation for your own system.</font> +<li> +<i><font size=-1>Pattern density</font></i></li> + +<br><font size=-1>There is a high pattern "density" around TestCase, which +is the key abstraction of JUnit. Designs with high pattern density are +easier to use but harder to change. We have found that such a high pattern +density around key abstractions is common for mature frameworks. The opposite +should be true of immature frameworks - they should have low pattern density. +Once you discover what problem you are really solving, then you can begin +to "compress" the solution, leading to a denser and denser field of patterns +where they provide leverage.</font> +<li> +<i><font size=-1>Eat your own dog food</font></i></li> + +<br><font size=-1>As soon as we had the base unit testing functionality +implemented, we applied it ourselves. A TestTest verifies that the framework +reports the correct results for errors, successes, and failures. We found +this invaluable as we continued to evolve the design of the framework. +We found that the most challenging application of JUnit was testing its +own behavior.</font> +<li> +<i><font size=-1>Intersection, not union</font></i></li> + +<br><font size=-1>There is a temptation in framework development to include +every feature you can. After all, you want to make the framework as valuable +as possible. However, there is a counteracting force- developers have to +decide to use your framework. The fewer features the framework has, the +easier it is to learn, the more likely a developer will use it. JUnit is +written in this style. It implements only those features absolutely essential +to running tests- running suites of tests, isolating the execution of tests +from each other, and running tests automatically. Sure, we couldn’t resist +adding some features but we were careful to put them into their own extensions +package (test.extensions). A notable member of this package is a TestDecorator +allowing execution of additional code before and after a test.</font> +<li> +<i><font size=-1>Framework writers read their code</font></i></li> + +<br><font size=-1>We spent far more time reading the JUnit code than we +spent writing it, and nearly as much time removing duplicate functionality +as we spent adding new functionality. We experimented aggressively with +the design, adding new classes and moving responsibility around in as many +different ways as we could imagine. We were rewarded (and are still being +rewarded) for our monomania by a continuous flow of insights into JUnit, +testing, object design, framework development, and opportunities for further +articles.</font></ul> +<font size=-1>The latest version of JUnit can be downloaded from http://www.junit.org.</font> +<p><b><font face="Arial"><font size=+1>5. Acknowledgements</font></font></b> +<p><font size=-1>Thanks to John Vlissides, Ralph Johnson, and Nick Edgar +for careful reading and gentle correction.</font> +</body> +</html> diff --git a/junit4/doc/faq/faq.htm b/junit4/doc/faq/faq.htm new file mode 100644 index 0000000..783557e --- /dev/null +++ b/junit4/doc/faq/faq.htm @@ -0,0 +1,2380 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"/> + <title>JUnit FAQ</title> + + <style type="text/css"> + + body { + font-style: normal; + font-weight: normal; + margin-left: 10pt; + margin-right: 10pt; + } + + a { + text-decoration: none; + } + + a:hover { + text-decoration: underline; + } + + .header { + color: black; + font-size: 125%; + font-weight: bold; + background: #33ff33; + padding-top: 2px; + padding-bottom: 2px; + padding-left: 5px; + margin-top: 25px; + } + + .code { + background: white; + border-left: 5px solid #33ff33; + } + + .code-red { + background: white; + border-left: 5px solid #cc0000; + } + + </style> + +</head> + +<body> + +<h1> + <font color="#33ff33">J</font><font color="#cc0000">U</font>nit FAQ +</h1> +<hr size="1"/> + + +<!-- + + Summary + +--> +<p> +<i> +JUnit is a simple, open source framework to write and run repeatable +tests. It is an instance of the xUnit architecture for unit testing +frameworks. +</i> +</p> +<hr size="1"/> +<p> +Edited by <a href="mailto:mike@clarkware.com">Mike Clark</a> +(<a href="http://www.clarkware.com">http://clarkware.com</a>) +</p> +<p> +Last modified on February 20, 2006 +</p> + +<hr/> + +<!-- + + Table of Contents + +--> + +<div class="header"> +Table of Contents +</div> +<ol> + <li> + <p> + <b><a href="#faqinfo">FAQ Info</a></b> + </p> + <ol> + <li><a href="#faqinfo_1">Who is responsible for this FAQ?</a></li> + <li><a href="#faqinfo_2">How can I contribute to this FAQ?</a></li> + <li><a href="#faqinfo_3">Where do I get the latest version of + this FAQ?</a></li> + </ol> + </li> + <li> + <p> + <b><a href="#overview">Overview</a></b> + </p> + <ol> + <li><a href="#overview_1">What is JUnit?</a></li> + <li><a href="#overview_2">Where is the JUnit home page?</a></li> + <li><a href="#overview_3">Where are the JUnit mailing lists and + forums?</a></li> + <li><a href="#overview_4">Where is the JUnit documentation?</a></li> + <li><a href="#overview_5">Where can I find articles on JUnit?</a></li> + <li><a href="#overview_6">What's the latest news on JUnit?</a></li> + <li><a href="#overview_7">How is JUnit licensed?</a></li> + <li><a href="#overview_8">What awards has JUnit won?</a></li> + </ol> + </li> + <li> + <p> + <b><a href="#started">Getting Started</a></b> + </p> + <ol> + <li><a href="#started_1">Where do I download JUnit?</a></li> + <li><a href="#started_2">How do I install JUnit?</a></li> + <li><a href="#started_3">How do I uninstall JUnit?</a></li> + <li><a href="#started_4">How do I ask questions?</a></li> + <li><a href="#started_5">How do I submit bugs, patches, or + feature requests?</a></li> + </ol> + </li> + <li> + <p> + <b><a href="#tests">Writing Tests</a></b> + </p> + <ol> + <li><a href="#tests_1">How do I write and run a simple test?</a></li> + <li><a href="#tests_2">How do I use a test fixture?</a></li> + <li><a href="#tests_4">How do I test a method that doesn't + return anything?</a></li> + <li><a href="#tests_5">Under what conditions should I test get() + and set() methods?</a></li> + <li><a href="#tests_6">Under what conditions should I not test + get() and set() methods?</a></li> + <li><a href="#tests_7">How do I write a test that passes when an + expected exception is thrown?</a></li> + <li><a href="#tests_8">How do I write a test that fails when an + unexpected exception is thrown?</a></li> + <li><a href="#tests_10">How do I test protected methods?</a></li> + <li><a href="#tests_11">How do I test private methods?</a></li> + <li><a href="#tests_12">Why does JUnit only report the first + failure in a single test?</a></li> + <li><a href="#tests_13">In Java 1.4, 'assert' is a + keyword. Won't this conflict with JUnit's assert() + method?</a></li> + <li><a href="#tests_14">How do I test things that must be run in + a J2EE container (e.g. servlets, EJBs)?</a></li> + <li><a href="#tests_15">Do I need to write a test class for + every class I need to test?</a></li> + <li><a href="#tests_16">Is there a basic template I can use to + create a test?</a></li> + <li><a href="#tests_17">How do I write a test for an abstract + class?</a></li> + <li><a href="#tests_18">When are tests garbage collected?</a></li> + </ol> + </li> + <li> + <p> + <b><a href="#organize">Organizing Tests</a></b> + </p> + <ol> + <li><a href="#organize_1">Where should I put my test files?</a></li> + <li><a href="#organize_3">How can I run setUp() and tearDown() + code once for all of my tests?</a></li> + </ol> + </li> + <li> + <p> + <b><a href="#running">Running Tests</a></b> + </p> + <ol> + <li><a href="#running_1">What CLASSPATH settings are needed to + run JUnit?</a></li> + <li><a href="#running_2">Why do I get a NoClassDefFoundError + when trying to test JUnit or run the samples?</a> + </li> + <li><a href="#running_4">How do I run JUnit from my command window?</a> + </li> + <li><a href="#running_5">How do I run JUnit using Ant?</a> + </li> + <li><a href="#running_6">How do I use Ant to create HTML test reports?</a> + </li> + <li><a href="#running_7">How do I pass command-line arguments to a test execution?</a> + </li> + <li><a href="#running_9">Why do I get a LinkageError when using + XML interfaces in my test class?</a> + </li> + <li><a href="#running_11">Why do I get the warning "AssertionFailedError: No + tests found in XXX" when I run my test?</a> + </li> + <li><a href="#running_12">Why do I see "Unknown Source" in the stack trace of + a test failure, rather than the source file's line number?</a> + </li> + <li><a href="#running_15">How do I organize all test classes in a TestSuite + automatically and not use or manage a TestSuite explicitly?</a> + </li> + </ol> + </li> + <li> + <p> + <b><a href="#best">Best Practices</a></b> + </p> + <ol> + <li><a href="#best_1">When should tests be written?</a></li> + <li><a href="#best_2">Do I have to write a test for + everything?</a></li> + <li><a href="#best_3">How simple is 'too simple to break'?</a></li> + <li><a href="#best_4">How often should I run my tests?</a></li> + <li><a href="#best_5">What do I do when a defect is reported?</a></li> + <li><a href="#best_6">Why not just use System.out.println()?</a></li> + <li><a href="#best_7">Why not just use a debugger?</a></li> + </ol> + </li> + <li> + <p> + <b><a href="#misc">Miscellaneous</a></b> + </p> + <ol> + <li><a href="#misc_1">How do I integrate JUnit with my IDE?</a></li> + <li><a href="#misc_2">How do I launch a debugger when a test + fails?</a></li> + <li><a href="#misc_3">Where can I find unit testing frameworks + similar to JUnit for other languages?</a></li> + </ol> + </li> + </ol> + +<!-- + + FAQ Info + +--> +<div class="header"> +<a name="faqinfo">FAQ Info</a> +</div> +<ol> + <li> + <p> + <b><a name="faqinfo_1">Who is responsible for this FAQ?</a></b> + </p> + <p> + The current version of this FAQ is maintained + by <a href="mailto:mike@clarkware.com">Mike Clark</a>. + </p> + <p> + Most of the wisdom contained in this FAQ comes from the + collective insights and hard-won experiences of the many good + folks who participate on the JUnit mailing list and the JUnit + community at large. + </p> + <p> + If you see your genius represented anywhere in this FAQ without + due credit to you, please send me an email and I'll make things + right. + </p> + </li> + <li> + <p> + <b><a name="faqinfo_2">How can I contribute to this FAQ?</a></b> + </p> + <p> + Your contributions to this FAQ are greatly appreciated! The + JUnit community thanks you in advance. + </p> + <p> + To contribute to this FAQ, simply write a JUnit-related question + and answer, then send the unformatted text + to <a href="mailto:mike@clarkware.com">Mike Clark</a>. + Corrections to this FAQ are always appreciated, as well. + </p> + <p> + No reasonable contribution will be denied. Your name will + always appear along with any contribution you make. + </p> + </li> + <li> + <p> + <b><a name="faqinfo_3">Where do I get the latest version of this + FAQ?</a></b> + </p> + <p> + The master copy of this FAQ is available + at <a + href="http://junit.sourceforge.net/doc/faq/faq.htm">http://junit.sourceforge.net/doc/faq/faq.htm</a>. + </p> + <p> + The JUnit distribution also includes this FAQ in + the <code>doc</code> directory. + </p> + </li> + +</ol> + + +<!-- + + Overview + +--> +<div class="header"> +<a name="overview">Overview</a> +</div> +<ol> + <li> + <p> + <b><a name="overview_1">What is JUnit?</a></b> + </p> + <p> + JUnit is a simple, open source framework to write and run + repeatable tests. It is an instance of the xUnit architecture + for unit testing frameworks. JUnit features include: + </p> + <ul> + <li>Assertions for testing expected results</li> + <li>Test fixtures for sharing common test data</li> + <li>Test runners for running tests</li> + </ul> + <p> + JUnit was originally written by Erich Gamma and Kent Beck. + </p> + </li> + <li> + <p> + <b><a name="overview_2">Where is the JUnit home page?</a></b> + </p> + <p> + The official JUnit home page is <a + href="http://junit.org">http://junit.org</a>. + </p> + </li> + <li> + <p> + <b><a name="overview_3">Where are the JUnit mailing lists and + forums?</a></b> + </p> + <p> + There are 3 mailing lists dedicated to everything JUnit: + </p> + <ul> + <li> + <a href="http://groups.yahoo.com/group/junit/">JUnit user + list</a>. (Search it for answers to frequently asked + questions not included here.) + </li> + <li> + <a + href="http://lists.sourceforge.net/lists/listinfo/junit-announce">JUnit + announcements</a> + </li> + <li> + <a + href="http://lists.sourceforge.net/lists/listinfo/junit-devel">JUnit + developer list</a> + </li> + </ul> + </li> + <li> + <p> + <b><a name="overview_4">Where is the JUnit + documentation?</a></b> + </p> + <p> + The following documents are included in the JUnit distribution + in the <code>doc</code> directory: + </p> + <ul> + <li> + <a + href="http://junit.sourceforge.net/doc/testinfected/testing.htm">JUnit + Test Infected: Programmers Love Writing Tests</a> + </li> + <li> + <a + href="http://junit.sourceforge.net/doc/cookbook/cookbook.htm">JUnit + Cookbook</a> + </li> + <li> + <a + href="http://junit.sourceforge.net/doc/cookstour/cookstour.htm">JUnit + - A Cook's Tour</a> + </li> + <li> + <a href="http://junit.sourceforge.net/doc/faq/faq.htm">JUnit + FAQ</a> + </li> + </ul> + </li> + <li> + <p> + <b><a name="overview_5">Where can I find articles on + JUnit?</a></b> + </p> + <p> + The JUnit home page maintains a list + of <a href="http://www.junit.org/news/article/index.htm">JUnit + articles</a>. + </p> + </li> + <li> + <p> + <b><a name="overview_6">What's the latest news on JUnit?</a></b> + </p> + <p> + The JUnit home page publishes + the <a href="http://www.junit.org/news/index.htm">latest JUnit + news</a>. + </p> + </li> + <li> + <p> + <b><a name="overview_7">How is JUnit licensed?</a></b> + </p> + <p> + JUnit is <a href="http://www.opensource.org/">Open Source + Software</a>, released + under <a + href="http://oss.software.ibm.com/developerworks/oss/license-cpl.html">IBM's + Common Public License Version 0.5</a> and hosted + on <a + href="http://sourceforge.net/projects/junit/">SourceForge</a>. + </p> + </li> + <li> + <p> + <b><a name="overview_8">What awards has JUnit won?</a></b> + </p> + <ul> + <li> + <p> <a + href="http://www.javaworld.com/javaworld/jw-03-2002/jw-0326-awards.html">2002 + JavaWorld Editors' Choice Awards (ECA)</a> + </p> + <p> + Best Java Performance Monitoring/Testing Tool + </p> + </li> + <li> + <p> + <a + href="http://www.javaworld.com/javaworld/jw-06-2001/j1-01-awards.html">2001 + JavaWorld Editors' Choice Awards (ECA)</a> + </p> + <p> + Best Java Performance Monitoring/Testing Tool + </p> + </li> + </ul> + </li> +</ol> + + +<!-- + + Getting Started + +--> +<div class="header"> +<a name="started">Getting Started</a> +</div> +<ol> + <li> + <p> + <b><a name="started_1">Where do I download JUnit?</a></b> + </p> + <p> + The latest version of JUnit is available + on <a + href="http://sourceforge.net/project/showfiles.php?group_id=15278">SourceForge</a>. + </p> + </li> + <li> + <p> + <b><a name="started_2">How do I install JUnit?</a></b> + </p> + <ol> + <li> + <p> + First, <a + href="http://sourceforge.net/project/showfiles.php?group_id=15278">download</a> + the + latest version of JUnit, referred to below + as <code>junit.zip</code>. + </p> + </li> + <li> + <p> + Then install JUnit on your platform of choice: + </p> + <p> + <u>Windows</u> + </p> + <p> + To install JUnit on Windows, follow these steps: + </p> + <ol> + <li> + <p> + Unzip the <code>junit.zip</code> distribution file to + a directory referred to as <code>%JUNIT_HOME%</code>. + </p> + </li> + <li>Add JUnit to the classpath: + <p> + <code>set CLASSPATH=%CLASSPATH%;%JUNIT_HOME%\junit.jar</code> + </p> + </li> + </ol> + <p> + <u>Unix (bash)</u> + </p> + <p> + To install JUnit on Unix, follow these steps: + </p> + <ol> + <li> + <p> + Unzip the <code>junit.zip</code> distribution file to + a directory referred to as <code>$JUNIT_HOME</code>. + </p> + </li> + <li> + <p> + Add JUnit to the classpath: + </p> + <p> + <code>export CLASSPATH=$CLASSPATH:$JUNIT_HOME/junit.jar</code> + </p> + </li> + </ol> + </li> + <li> + <p> + <i>(Optional)</i> Unzip + the <code>$JUNIT_HOME/src.jar</code> file. + </p> + </li> + <li> + <p> + Test the installation by running the sample tests + distributed with JUnit. Note that the sample tests are + located in the installation directory directly, not + the <code>junit.jar</code> file. Therefore, make sure that + the JUnit installation directory is on your CLASSPATH. Then + simply type: + </p> + <div> + <blockquote><code> + java org.junit.runner.JUnitCore org.junit.tests.AllTests + </code></blockquote> + </div> + <p> + All the tests should pass with an "OK" message. + </p> + <p> + <i> + If the tests don't pass, verify + that <code>junit.jar</code> is in the CLASSPATH. + </i> + </p> + </li> + <li> + <p> + Finally, <a href="#overview_4">read</a> the documentation. + </p> + </li> + </ol> + </li> + <li> + <p> + <b><a name="started_3">How do I uninstall JUnit?</a></b> + </p> + <ol> + <li> + <p> + Delete the directory structure where you unzipped the JUnit + distribution. + </p> + </li> + <li> + <p> + Remove <code>junit.jar</code> from the CLASSPATH. + </p> + </li> + </ol> + <p> + JUnit does not modify the registry so simply removing all the + files will fully uninstall it. + </p> + </li> + <li> + <p> + <b><a name="started_4">How do I ask questions?</a></b> + </p> + <p> + Questions that are not answered in + the <a + href="http://junit.sourceforge.net/doc/faq/faq.htm">FAQ</a> or + in the <a href="#overview_4">documentation</a> should be posted + to + the <a + href="http://www.jguru.com/forums/home.jsp?topic=JUnit">jGuru + discussion forum</a> or the <a + href="http://groups.yahoo.com/group/junit/">JUnit user mailing + list</a>. + </p> + <p> + Please stick to technical issues on the discussion forum and + mailing lists. Keep in mind that these are public, so + do <b>not</b> include any confidental information in your + questions! + </p> + <p> + You should also + read <a + href="http://www.catb.org/~esr/faqs/smart-questions.html">"How + to ask questions the smart way"</a> by Eric Raymond before + participating in the discussion forum and mailing lists. + </p> + <p> + <i> + NOTE: <br/> Please do NOT submit bugs, patches, or feature + requests to the discussion forum or mailing lists. <br/> + Refer instead to <a href="#started_5">"How do I submit bugs, + patches, or feature requests?"</a>. + </i> + </p> + </li> + <li> + <p> + <b><a name="started_5">How do I submit bugs, patches, or + feature requests?</a></b> + </p> + <p> + JUnit celebrates programmers testing their own software. In this + spirit, bugs, patches, and feature requests that include JUnit + tests have a better chance of being addressed than those + without. + </p> + <p> + JUnit is hosted + on <a + href="http://sourceforge.net/projects/junit">SourceForge</a>. + Please use the tools provided by SourceForge for your + submissions. + </p> + </li> +</ol> + + +<!-- + + Writing Tests + +--> +<div class="header"> +<a name="tests">Writing Tests</a> +</div> +<ol> + <li> + <p> + <b><a name="tests_1"></a>How do I write and run a simple test?</b> + </p> + <ol> + <li> + <p> + Create a class: + </p> + <div class="code"> + <pre><code> + + package junitfaq; + + import org.junit.*; + import static org.junit.Assert.*; + + import java.util.*; + + public class SimpleTest { + </code></pre> + </div> + </li> + <li> + <p> + Write a test method (annotated with <code>@Test</code>) that + asserts expected results on the object under test: + </p> + <div class="code"> + <pre><code> + + @Test + public void testEmptyCollection() { + Collection collection = new ArrayList(); + assertTrue(collection.isEmpty()); + } + </code></pre> + </div> + </li> + <li> + <p> + If you are running your JUnit 4 tests with a JUnit 3.x runner, + write a <code>suite()</code> method that uses the + <code>JUnit4TestAdapter</code> class to create a suite + containing all of your test methods: + </p> + <div class="code"> + <pre><code> + + public static junit.framework.Test suite() { + return new junit.framework.JUnit4TestAdapter(SimpleTest.class); + } + </code></pre> + </div> + </li> + <li> + <p> + Although writing a <code>main()</code> method to run the + test is much less important with the advent of IDE runners, + it's still possible: + </p> + <div class="code"> + <pre><code> + + public static void main(String args[]) { + org.junit.runner.JUnitCore.main("junitfaq.SimpleTest"); + } + } + </code></pre> + </div> + </li> + <li> + <p> + Run the test: + </p> + <ul> + <li> + <p> + To run the test from the console, type: + </p> + <div> + <blockquote><code> +java org.junit.runner.JUnitCore junitfaq.SimpleTest + </code></blockquote> + </div> + </li> + <li> + <p> + To run the test with the test runner used + in <code>main()</code>, type: + </p> + <div> + <blockquote><code> +java junitfaq.SimpleTest + </code></blockquote> + </div> + </li> + </ul> + <p> + The passing test results in the following textual output: + </p> + <div> + <blockquote> + <pre><code> + . +Time: 0 + +OK (1 tests) + </code></pre> + </blockquote> + </div> + </li> + </ol> + </li> + <li> + <p> + <b><a name="tests_2"></a>How do I use a test fixture?</b> + </p> + <p> + <i>(Submitted by: Jeff Nielsen)</i> + </p> + <p> + A test fixture is useful if you have two or more tests for a + common set of objects. Using a test fixture avoids duplicating + the code necessary to initialize (and cleanup) the common + objects. + </p> + <p> + Tests can use the objects (variables) in a test fixture, with + each test invoking different methods on objects in the fixture + and asserting different expected results. Each test runs in its + own test fixture to isolate tests from the changes made by other + tests. That is, <em>tests don't share the state of objects in + the test fixture</em>. Because the tests are isolated, they can + be run in any order. + </p> + <p> + To create a test fixture, declare instance variables for the + common objects. Initialize these objects in a <code>public + void</code> method annotated with <code>@Before</code>. The + JUnit framework automatically invokes any <code>@Before</code> + methods before each test is run. + </p> + <p> + The following example shows a test fixture with a common + <code>Collection</code> object. + </p> + <div class="code"> + <pre><code> + package junitfaq; + + import org.junit.*; + import static org.junit.Assert.*; + import java.util.*; + + public class SimpleTest { + + private Collection<Object> collection; + + @Before + public void setUp() { + collection = new ArrayList<Object>(); + } + + @Test + public void testEmptyCollection() { + assertTrue(collection.isEmpty()); + } + + + @Test + public void testOneItemCollection() { + collection.add("itemA"); + assertEquals(1, collection.size()); + } + } + </code></pre> + </div> + + <p> + Given this test, the methods might execute in the following + order: + </p> + <blockquote> + <pre><code>setUp() +testEmptyCollection() +setUp() +testOneItemCollection()</code></pre> + </blockquote> + <p> + The ordering of test-method invocations is not guaranteed, so + <code>testOneItemCollection()</code> might be executed before + <code>testEmptyCollection()</code>. But it doesn't matter, + because each method gets its own instance of the + <code>collection</code>. + </p> + + <p> + Although JUnit provides a new instance of the fixture objects + for each test method, if you allocate any <em>external</em> + resources in a <code>@Before</code> method, you should release + them after the test runs by annotating a method with + <code>@After</code>. The JUnit framework automatically invokes + any <code>@After</code> methods after each test is run. For + example: + </p> + + <div class="code"> + <pre><code> + package junitfaq; + + import org.junit.*; + import static org.junit.Assert.*; + import java.io.*; + + public class OutputTest { + + private File output; + + @Before + public void createOutputFile() { + output = new File(...); + } + + @After + public void deleteOutputFile() { + output.delete(); + } + + @Test + public void testSomethingWithFile() { + ... + } + } + </code></pre> + </div> + <p> + With this test, the methods will execute in the following order: + </p> + <div> + <blockquote> + <pre><code> +createOutputFile() +testSomethingWithFile() +deleteOutputFile() + </code></pre> + </blockquote> + </div> + + </li> + <li> + <p> + <b><a name="tests_4"></a>How do I test a method that doesn't + return anything?</b> + </p> + <p> + <i>(Submitted by: Dave Astels)</i> + </p> + <p> + Often if a method doesn't return a value, it will have some side + effect. Actually, if it doesn't return a value AND doesn't have + a side effect, it isn't doing anything. + </p> + <p> + There may be a way to verify that the side effect actually + occurred as expected. For example, consider + the <code>add()</code> method in the Collection classes. There + are ways of verifying that the side effect happened (i.e. the + object was added). You can check the size and assert that it is + what is expected: + </p> + <div class="code"> + <pre><code> + + @Test + public void testCollectionAdd() { + Collection collection = new ArrayList(); + assertEquals(0, collection.size()); + collection.add("itemA"); + assertEquals(1, collection.size()); + collection.add("itemB"); + assertEquals(2, collection.size()); + } + </code></pre> + </div> + <p> + Another approach is to make use of <a + href="http://www.mockobjects.com">MockObjects</a>. + </p> + <p> + A related issue is to design for testing. For example, if you + have a method that is meant to output to a file, don't pass in a + filename, or even a <code>FileWriter</code>. Instead, pass in + a <code>Writer</code>. That way you can pass in + a <code>StringWriter</code> to capture the output for testing + purposes. Then you can add a method + (e.g. <code>writeToFileNamed(String filename)</code>) to + encapsulate the <code>FileWriter</code> creation. + </p> + </li> + <li> + <p> + <b><a name="tests_5"></a>Under what conditions should I test + get() and set() methods?</b> + </p> + <p> + Unit tests are intended to alleviate fear that something might + break. If you think a <code>get()</code> or <code>set()</code> + method could reasonably break, or has in fact contributed to a + defect, then by all means write a test. + </p> + <p> + In short, test until you're confident. What you choose to test + is subjective, based on your experiences and confidence level. + Remember to be practical and maximize your testing investment. + </p> + <p> + Refer also to <a href="#best_3">"How simple is 'too simple to + break'?"</a>. + </p> + </li> + <li> + <p> + <b><a name="tests_6"></a>Under what conditions should I not test + get() and set() methods?</b> + </p> + <p> + <i>(Submitted by: J. B. Rainsberger)</i> + </p> + <p> + Most of the time, get/set methods just can't break, and if they + can't break, then why test them? While it is usually better to + test more, there is a definite curve of diminishing returns on + test effort versus "code coverage". Remember the maxim: "Test + until fear turns to boredom." + </p> + <p> + Assume that the <code>getX()</code> method only does "return x;" + and that the <code>setX()</code> method only does "this.x = + x;". If you write this test: + </p> + <div> + <blockquote><pre> +@Test +public void testGetSetX() { + setX(23); + assertEquals(23, getX()); +} + </pre></blockquote> + </div> + <p> + then you are testing the equivalent of the following: + </p> + <div> + <blockquote><pre> +@Test +public void testGetSetX() { + x = 23; + assertEquals(23, x); +} +</pre></blockquote> + </div> + <p> + or, if you prefer, + </p> + <div> + <blockquote><pre> +@Test +public void testGetSetX() { + assertEquals(23, 23); +} +</pre></blockquote> + </div> + <p> + At this point, you are testing the Java compiler, or possibly + the interpreter, and not your component or application. There is + generally no need for you to do Java's testing for them. + </p> + <p> + If you are concerned about whether a property has already been + set at the point you wish to call <code>getX()</code>, then you + want to test the constructor, and not the <code>getX()</code> + method. This kind of test is especially useful if you have + multiple constructors: + </p> + <div> + <blockquote><pre> +@Test +public void testCreate() { + assertEquals(23, new MyClass(23).getX()); +} + </pre></blockquote> + </div> + </li> + <li> + <p> + <b><a name="tests_7"></a>How do I write a test that passes when + an expected exception is thrown?</b> + </p> + <p> + Add the optional <code>expected</code> attribute to + the <code>@Test</code> annotation. The following is an example + test that passes when the + expected <code>IndexOutOfBoundsException</code> is raised: + </p> + <div class="code"> + <pre><code> + + @Test(expected=IndexOutOfBoundsException.class) + public void testIndexOutOfBoundsException() { + ArrayList emptyList = new ArrayList(); + Object o = emptyList.get(0); + } + </code></pre> + </div> + </li> + <li> + <p> + <b><a name="tests_8"></a>How do I write a test that fails when + an unexpected exception is thrown?</b> + </p> + <p> + Declare the exception in the <code>throws</code> clause of the + test method and don't catch the exception within the test + method. Uncaught exceptions will cause the test to fail with an + error. + </p> + <p> + The following is an example test that fails when + the <code>IndexOutOfBoundsException</code> is raised: + </p> + <div class="code-red"> + <pre><code> + + @Test + public void testIndexOutOfBoundsExceptionNotRaised() + throws IndexOutOfBoundsException { + + ArrayList emptyList = new ArrayList(); + Object o = emptyList.get(0); + } + </code></pre> + </div> + </li> + <li> + <p> + <b><a name="tests_10"></a>How do I test protected methods?</b> + </p> + <p> + Place your tests in the same package as the classes under test. + </p> + <p> + Refer to <a href="#organize_1">"Where should I put my test + files?"</a> for examples of how to organize tests for protected + method access. + </p> + </li> + <li> + <p> + <b><a name="tests_11"></a>How do I test private methods?</b> + </p> + <p> + Testing private methods may be an indication that those methods + should be moved into another class to promote reusability. + </p> + <p> + But if you must... + </p> + <p> + If you are using JDK 1.3 or higher, you can use reflection to + subvert the access control mechanism with the aid of + the <a + href="http://sourceforge.net/projects/privaccessor/">PrivilegedAccessor</a>. + For details on how to use it, + read <a + href="http://www.onjava.com/pub/a/onjava/2003/11/12/reflection.html">this + article</a>. + </p> + </li> + <li> + <p> + <b><a name="tests_12"></a>Why does JUnit only report the first + failure in a single test?</b> + </p> + <p> + <i>(Submitted by: J. B. Rainsberger)</i> + </p> + <p> + Reporting multiple failures in a single test is generally a sign + that the test does too much, compared to what a unit test ought + to do. Usually this means either that the test is really a + functional/acceptance/customer test or, if it is a unit test, + then it is too big a unit test. + </p> + <p> + JUnit is designed to work best with a number of small tests. It + executes each test within a separate instance of the test + class. It reports failure on each test. Shared setup code is + most natural when sharing between tests. This is a design + decision that permeates JUnit, and when you decide to report + multiple failures per test, you begin to fight against + JUnit. This is not recommended. + </p> + <p> + Long tests are a design smell and indicate the likelihood of a + design problem. Kent Beck is fond of saying in this case that + "there is an opportunity to learn something about your design." + We would like to see a pattern language develop around these + problems, but it has not yet been written down. + </p> + <p> + Finally, note that a single test with multiple assertions is + isomorphic to a test case with multiple tests: + </p> + <p> + One test method, three assertions: + </p> + <div> + <blockquote><pre><code> +public class MyTestCase { + @Test + public void testSomething() { + // Set up for the test, manipulating local variables + assertTrue(condition1); + assertTrue(condition2); + assertTrue(condition3); + } +} + </code></pre></blockquote> + </div> + <p> + Three test methods, one assertion each: + </p> + <div> + <blockquote><pre><code> +public class MyTestCase { + // Local variables become instance variables + + @Before + public void setUp() { + // Set up for the test, manipulating instance variables + } + + @Test + public void testCondition1() { + assertTrue(condition1); + } + + @Test + public void testCondition2() { + assertTrue(condition2); + } + + @Test + public void testCondition3() { + assertTrue(condition3); + } +} + </code></pre></blockquote> + </div> + <p> + The resulting tests use JUnit's natural execution and reporting + mechanism and, failure in one test does not affect the execution + of the other tests. You generally want exactly one test to fail + for any given bug, if you can manage it. + </p> + </li> + <li> + <p> + <b><a name="tests_13"></a>In Java 1.4, <code>assert</code> is a + keyword. Won't this conflict + with JUnit's <code>assert()</code> method?</b> + </p> + <p> + JUnit 3.7 deprecated <code>assert()</code> and replaced it + with <code>assertTrue()</code>, which works exactly the same + way. + </p> + <p> + JUnit 4 is compatible with the <code>assert</code> keyword. If + you run with the <code>-ea</code> JVM switch, assertions that + fail will be reported by JUnit. + </p> + </li> + <li> + <p> + <b><a name="tests_14"></a>How do I test things that must be run + in a J2EE container (e.g. servlets, EJBs)?</b> + </p> + <p> + Refactoring J2EE components to delegate functionality to other + objects that don't have to be run in a J2EE container will + improve the design and testability of the software. + </p> + <p> + <a href="http://jakarta.apache.org/cactus/index.html">Cactus</a> + is an open source JUnit extension that can be used to test J2EE + components in their natural environment. + </p> + </li> + <li> + <p> + <b><a name="tests_15"></a>Do I need to write + a test class for every class I need to + test?</b> + </p> + <p> + <i>(Submitted by: J. B. Rainsberger)</i> + </p> + <p> + No. It is a convention to start with one test + class per class under test, but it is not necessary. + </p> + <p> + Test classes only provide a way to organize tests, nothing more. + Generally you will start with one test class per class under + test, but then you may find that a small group of tests belong + together with their own common test fixture.[1] In this case, + you may move those tests to a new test class. This is a simple + object-oriented refactoring: separating responsibilities of an + object that does too much. + </p> + <p> + Another point to consider is that the <code>TestSuite</code> is + the smallest execution unit in JUnit: you cannot execute + anything smaller than a TestSuite at one time without changing + source code. In this case, you probably do not want to put tests + in the same test class unless they somehow "belong together". + If you have two groups of tests that you think you'd like to + execute separately from one another, it is wise to place them in + separate test classes. + </p> + <p> + <i> + [1] A test fixture is a common set of test data and + collaborating objects shared by many tests. Generally they are + implemented as instance variables in the test class. + </i> + </p> + </li> + <li> + <p> + <b><a name="tests_16"></a>Is there a basic template I can use to + create a test?</b> + </p> + <p> + <i>(Submitted by: Eric Armstrong)</i> + </p> + <p> + The following templates are a good starting point. Copy/paste + and edit these templates to suit your coding style. + </p> + <p> + SampleTest is a basic test template: + </p> + <div> + <blockquote><pre><code> +import org.junit.*; +import static org.junit.Assert.*; + +public class SampleTest { + + private java.util.List emptyList; + + /** + * Sets up the test fixture. + * (Called before every test case method.) + */ + @Before + public void setUp() { + emptyList = new java.util.ArrayList(); + } + + /** + * Tears down the test fixture. + * (Called after every test case method.) + */ + @After + public void tearDown() { + emptyList = null; + } + + @Test + public void testSomeBehavior() { + assertEquals("Empty list should have 0 elements", 0, emptyList.size()); + } + + @Test(expected=IndexOutOfBoundsException.class) + public void testForException() { + Object o = emptyList.get(0); + } +} + </code></pre></blockquote> + </div> + </li> + <li> + <p> + <b><a name="tests_17"></a>How do I write a test for an abstract + class?</b> + </p> + <p> + Refer to <a + href="http://c2.com/cgi/wiki?AbstractTestCases">http://c2.com/cgi/wiki?AbstractTestCases</a>. + </p> + </li> + <li> + <p> + <b><a name="tests_18"></a>When are tests garbage collected?</b> + </p> + <p> + <i>(Submitted by: Timothy Wall and Kent Beck)</i> + </p> + <p> + By design, the tree of Test instances is built in one pass, then + the tests are executed in a second pass. The test runner holds + strong references to all Test instances for the duration of the + test execution. This means that for a very long test run with + many Test instances, none of the tests may be garbage collected + until the end of the entire test run. + </p> + <p> + Therefore, if you allocate external or limited resources in a + test, you are responsible for freeing those resources. + Explicitly setting an object to <code>null</code> in + the <code>tearDown()</code> method, for example, allows it to be + garbage collected before the end of the entire test run. + </p> + </li> +</ol> + + +<!-- + + Organizing Tests + +--> +<div class="header"> +<a name="organize">Organizing Tests</a> +</div> +<ol> + <li> + <p> + <b><a name="organize_1"></a>Where should I put my test files?</b> + </p> + <p> + You can place your tests in the same package and directory as + the classes under test. + </p> + <p> + For example: + </p> + <div> + <blockquote><pre> +src + com + xyz + SomeClass.java + SomeClassTest.java + </pre></blockquote> + </div> + <p> + While adequate for small projects, many developers feel that + this approach clutters the source directory, and makes it hard + to package up client deliverables without also including + unwanted test code, or writing unnecessarily complex packaging + tasks. + </p> + <p> + An arguably better way is to place the tests in a separate + parallel directory structure with package alignment. + </p> + <p> + For example: + </p> + <div> + <blockquote><pre> +src + com + xyz + SomeClass.java +test + com + xyz + SomeClassTest.java + </pre></blockquote> + </div> + <p> + These approaches allow the tests to access to all the public and + package visible methods of the classes under test. + </p> + <p> + Some developers have argued in favor of putting the tests in a + sub-package of the classes under test (e.g. com.xyz.test). The + author of this FAQ sees no clear advantage to adopting this + approach and believes that said developers also put their curly + braces on the wrong line. :-) + </p> + </li> + <li> + <p> + <b><a name="organize_3"></a>How can I run setUp() and tearDown() + code once for all of my tests?</b> + </p> + <p> + The desire to do this is usually a symptom of excessive coupling + in your design. If two or more tests must share the same test + fixture state, then the tests may be trying to tell you that the + classes under test have some undesirable dependencies. + </p> + <p> + Refactoring the design to further decouple the classes under + test and eliminate code duplication is usually a better + investment than setting up a shared test fixture. + </p> + <p> + But if you must... + </p> + <p> + You can add a <code>@BeforeClass</code> annotation to a method + to be run before all the tests in a class, and + a <code>@AfterClass</code> annotation to a method to be run + after all the tests in a class. Here's an example: + </p> + <div class="code"> + <pre><code> + + package junitfaq; + + import org.junit.*; + import static org.junit.Assert.*; + import java.util.*; + + public class SimpleTest { + + private Collection collection; + + @BeforeClass + public static void oneTimeSetUp() { + // one-time initialization code + } + + @AfterClass + public static void oneTimeTearDown() { + // one-time cleanup code + } + + @Before + public void setUp() { + collection = new ArrayList(); + } + + @After + public void tearDown() { + collection.clear(); + } + + @Test + public void testEmptyCollection() { + assertTrue(collection.isEmpty()); + } + + @Test + public void testOneItemCollection() { + collection.add("itemA"); + assertEquals(1, collection.size()); + } + } + </code></pre> + </div> + <p> + Given this test, the methods will execute in the following + order: + </p> + <div> + <blockquote> + <pre><code> +oneTimeSetUp() +setUp() +testEmptyCollection() +tearDown() +setUp() +testOneItemCollection() +tearDown() +oneTimeTearDown() + </code></pre> + </blockquote> + </div> + + </li> +</ol> + + +<!-- + + Running Tests + +--> +<div class="header"> +<a name="running">Running Tests</a> +</div> +<ol> + <li> + <p> + <b><a name="running_1"></a>What CLASSPATH settings are needed to + run JUnit?</b> + </p> + <p> + <i>(Submitted by: Eric Armstrong)</i> + </p> + <p> + To run your JUnit tests, you'll need the following elemements in + your CLASSPATH: + </p> + <ul> + <li>JUnit class files</li> + <li>Your class files, including your JUnit test classes</li> + <li>Libraries your class files depend on</li> + </ul> + <p> + If attempting to run your tests results in + a <code>NoClassDefFoundError</code>, then something is missing + from your CLASSPATH. + </p> + <p> + <u>Windows Example:</u> + </p> + <p> + <code>set + CLASSPATH=%JUNIT_HOME%\junit.jar;c:\myproject\classes;c:\myproject\lib\something.jar</code> + </p> + <p> + <u>Unix (bash) Example:</u> + </p> + <p> + <code>export CLASSPATH=$JUNIT_HOME/junit.jar:/myproject/classes:/myproject/lib/something.jar</code> + </p> + </li> + <li> + <p> + <b><a name="running_2"></a>Why do I get + a <code>NoClassDefFoundError</code> when trying to test JUnit + or run the samples?</b> + </p> + <p> + <i>(Submitted by: J.B. Rainsberger and Jason Rogers)</i> + </p> + <p> + Most likely your CLASSPATH doesn't include the JUnit + installation directory. + </p> + <p> + Refer to <a href="#running_1">"What CLASSPATH settings are + needed to run JUnit?"</a> for more guidance. + </p> + <p> + Also consider running <a + href="http://www.clarkware.com/software/WhichJUnit.zip">WhichJunit</a> + to print the absolute location of the JUnit class files required + to run and test JUnit and its samples. + </p> + <p> + If the CLASSPATH seems mysterious, read <a + href="http://java.sun.com/j2se/1.4/docs/tooldocs/findingclasses.html">this</a>! + </p> + </li> + <li> + <p> + <b><a name="running_4"></a>How do I run JUnit from my command window?</b> + </p> + <p> + <i>(Submitted by: Eric Armstrong)</i> + </p> + <ol> + <li> + <p> + <a href="#running_1">Set your CLASSPATH</a> + </p> + </li> + <li> + <p> + Invoke the runner: + </p> + <p> + <code> + java org.junit.runner.JUnitCore <test class name> + </code> + </p> + </li> + </ol> + </li> + <li> + <p> + <b><a name="running_5"></a>How do I run JUnit using Ant?</b> + </p> + <p> + <i>(Submitted by: Eric Armstrong)</i> + </p> + <ol> + <li> + <p> + Define any necessary Ant properties: + </p> + <div> + <pre><code> +<property name="src" value="./src" /> +<property name="lib" value="./lib" /> +<property name="classes" value="./classes" /> +<property name="test.class.name" value="com.xyz.MyTestSuite" /> + </code></pre> + </div> + </li> + <li> + <p> + Set up the CLASSPATH to be used by JUnit: + </p> + <div> + <pre><code> +<path id="test.classpath"> + <pathelement location="${classes}" /> + <pathelement location="/path/to/junit.jar" /> + <fileset dir="${lib}"> + <include name="**/*.jar"/> + </fileset> +</path> + </code></pre> + </div> + </li> + <li> + <p> + Define the Ant task for running JUnit: + </p> + <div> + <pre><code> +<target name="test"> + <junit fork="yes" haltonfailure="yes"> + <test name="${test.class.name}" /> + <formatter type="plain" usefile="false" /> + <classpath refid="test.classpath" /> + </junit> +</target> + </code></pre> + </div> + </li> + <li> + <p> + Run the test: + </p> + <div> + <code> + ant test + </code> + </div> + </li> + </ol> + <p> + Refer to the <a + href="http://jakarta.apache.org/ant/manual/OptionalTasks/junit.html">JUnit + Ant Task</a> for more information. + </p> + </li> + <li> + <p> + <b><a name="running_6"></a>How do I use Ant to create HTML test + reports?</b> + </p> + <p> + <i>(Submitted by: Eric Armstrong and Steffen Gemkow)</i> + </p> + <ol> + <li> + <p> + Ensure that Ant's <code>optional.jar</code> file is either + in your CLASSPATH or exists in + your <code>$ANT_HOME/lib</code> directory. + </p> + </li> + <li> + <p> + Add an ANT property for the directory containing the HTML reports: + </p> + <div> + <code> +<property name="test.reports" value="./reports" /> + </code> + </div> + </li> + <li> + <p> + Define the Ant task for running JUnit and generating reports: + </p> + <div> + <pre><code> +<target name="test-html"> + <junit fork="yes" printsummary="no" haltonfailure="no"> + <batchtest fork="yes" todir="${test.reports}" > + <fileset dir="${classes}"> + <include name="**/*Test.class" /> + </fileset> + </batchtest> + <formatter type="xml" /> + <classpath refid="test.classpath" /> + </junit> + + <junitreport todir="${test.reports}"> + <fileset dir="${test.reports}"> + <include name="TEST-*.xml" /> + </fileset> + <report todir="${test.reports}" /> + </junitreport> +</target> + </code></pre> + </div> + </li> + <li> + <p> + Run the test: + </p> + <div> + <code> + ant test-html + </code> + </div> + </li> + </ol> + <p> + Refer to the + <a href="http://jakarta.apache.org/ant/manual/OptionalTasks/junit.html">JUnit Ant Task</a> + for more information. + </p> + </li> + <li> + <p> + <b><a name="running_7"></a>How do I pass command-line arguments + to a test execution?</b> + </p> + <p> + Use the <tt>-D</tt> JVM command-line options, as in: + </p> + <div> + <blockquote><code> +-DparameterName=parameterValue + </code></blockquote> + </div> + <p> + If the number of parameters on the command line gets unweildy, + pass in the location of a property file that defines a set of + parameters. Alternatively, the <a + href="http://junit-addons.sf.net">JUnit-addons package</a> + contains the <tt>XMLPropertyManager</tt> + and <tt>PropertyManager</tt> classes that allow you to define a + property file (or XML file) containing test parameters. + </p> + </li> + <li> + <p> + <b><a name="running_9"></a>Why do I get + a <code>LinkageError</code> when using + XML interfaces in my test?</b> + </p> + <p> + <i>(Submitted by: Scott Stirling)</i> + </p> + <p> + The workaround as of JUnit 3.7 is to + add <code>org.w3c.dom.*</code> and <code>org.xml.sax.*</code> to + your <code>excluded.properties</code>. + </p> + <p> + It's just a matter of time before this fix becomes incorporated + into the released version of + JUnit's <code>excluded.properties</code>, since JAXP is a + standard part of JDK 1.4. It will be just like + excluding <code>org.omg.*</code>. By the way, if you download + the JUnit source from its Sourceforge CVS, you will find that + these patterns have already been added to the default + excluded.properties and so has a pattern for JINI. In fact, here + is the current version in CVS, which demonstrates how to add + exclusions to the list too: + </p> + <div> + <blockquote><pre> +# +# The list of excluded package paths for the TestCaseClassLoader +# +excluded.0=sun.* +excluded.1=com.sun.* +excluded.2=org.omg.* +excluded.3=javax.* +excluded.4=sunw.* +excluded.5=java.* +excluded.6=org.w3c.dom.* +excluded.7=org.xml.sax.* +excluded.8=net.jini.* + </pre></blockquote> + </div> + <p> + This is the most common case where the + default <code>excluded.properties</code> list needs + modification. The cause of the <code>LinkageError</code> is + related to using JAXP in your test cases. By JAXP I mean the + whole set of <code>javax.xml.*</code> classes and the + supporting <code>org.w3c.dom.*</code> + and <code>org.xml.sax.*</code> classes. + </p> + <p> + As stated above, the JUnit GUI TestRunners' classloader relies + on the <code>excluded.properties</code> for classes it should + delegate to the system classloader. JAXP is an unusual case + because it is a standard Java extension library dependent on + classes whose package names (<code>org.w3c.dom.*</code> + and <code>org.xml.sax.*</code>) do not begin with a standard + Java or Sun prefix. This is similar to the relationship + between <code>javax.rmi.*</code> and the <code>org.omg.*</code> + classes, which have been excluded by default in + JUnit'ss <code>excluded.properties</code> for a while. + </p> + <p> + What can happen, and frequently does when using the JUnit Swing + or AWT UI with test cases that reference, use or depend on JAXP + classes, such as Log4J, Apache SOAP, Axis, Cocoon, etc., is that + the JUnit class loader (properly) + delegates <code>javax.xml.*</code> classes it "sees" + to the system loader. But then the system loader, in the process + of initializing and loading that JAXP class, links and loads up + a bunch of <code>org.w3c.dom</code>/<code>org.xml.sax</code> + classes. When it does so, the JUnit custom classloader is not + involved at all because the system classloader never delegates + "down" or checks with custom classloaders to see if a + class is already loaded. At any point after this, if the JUnit + loader is asked to load + an <code>org.w3c.dom</code>/<code>org.xml.sax</code> class that + it's never seen before, it will try to load it because the + class' name doesn't match any of the patterns in the default + exclude list. That's when a <code>LinkageError</code> + occurs. This is really a flaw in the JUnit classloader design, + but there is the workaround given above. + </p> + <p> + Java 2 JVMs keep classes (remember, classes and objects, though + related, are different entities to the JVM - I'm talking + about classes here, not object instances) in namespaces, + identifying them by their fully qualified classname plus the + instance of their defining (not initiating) loader. The JVM will + attempt to assign all unloaded classes referenced by an already + defined and loaded class to that class's defining loader. The + JVM's classresolver routine (implemented as a C function in the + JVM source code) keeps track of all these class loading events + and "sees" if another classloader (such as the JUnit + custom loader) attempts to define a class that has already been + defined by the system loader. According to the rules of Java 2 + loader constraints, in case a class has already been defined by + the system loader, any attempts to load a class should first be + delegated to the system loader. A "proper" way for + JUnit to handle this feature would be to load classes from a + repository other than the CLASSPATH that the system classloader + knows nothing about. And then the JUnit custom classloader could + follow the standard Java 2 delegation model, which is to always + delegate class loading to the system loader, and only attempt to + load if that fails. Since they both load from the CLASSPATH in + the current model, if the JUnit loader delegated like it's + supposed to, it would never get to load any classes since the + system loader would always find them. + </p> + <p> + You could try to hack around this in the JUnit source by + catching the <code>LinkageError</code> in + TestCaseClassLoader's <code>loadClass()</code> method and then + making a recovery call to <code>findSystemClass()</code> -- + thereby delegating to the system loader after the violation has + been caught. But this hack only works some of the time, because + now you can have the reverse problem where the JUnit loader will + load a host of <code>org.w3c.dom</code>/<code>org.xml.sax</code> + classes, and then the system loader violates the loader + contraints at some point when it tries to do exactly what I + described above with JAXP because it doesn't ever delegate to + its logical child (the JUnit loader). Inevitably, if your test + cases use many JAXP and related XML classes, one or the other + classloader will end up violating the constraints whatever you + do. + </p> + </li> + <li> + <p> + <b><a name="running_11"></a>Why do I get the warning + "AssertionFailedError: No + tests found in XXX" when I run my test?</b> + </p> + <p> + Make sure you have more or more method annotated with <code>@Test</code>. + </p> + <p> + For example: + </p> + <div> + <blockquote><pre> +@Test +public void testSomething() { +} + </pre></blockquote> + </div> + </li> + <li> + <p> + <b><a name="running_12"></a>Why do I see "Unknown Source" in the + stack trace of +a test failure, rather than the source file's line number?</b> + </p> + <p> + The debug option for the Java compiler must be enabled in order + to see source file and line number information in a stack trace. + </p> + <p> + When invoking the Java compiler from the command line, use + the <code>-g</code> option to generate all debugging info. + </p> + <p> + When invoking the Java compiler from an + <a href="http://jakarta.apache.org/ant/index.html">Ant</a> task, use the + <code>debug="on"</code> attribute. For example: + </p> + <div> + <blockquote><code> +<javac srcdir="${src}" destdir="${build}" debug="on" /> + </code></blockquote> + </div> + <p> + When using older JVMs pre-Hotspot (JDK 1.1 and most/all 1.2), + run JUnit with the <code>-DJAVA_COMPILER=none</code> JMV command + line argument to prevent runtime JIT compilation from obscuring + line number info. + </p> + <p> + Compiling the test source with debug enabled will show the line + where the assertion failed. Compiling the non-test source with + debug enabled will show the line where an exception was raised + in the class under test. + </p> + </li> + <li> + <p> + <b><a name="running_15"></a>How do I organize all test classes + in a TestSuite automatically and not use or manage a TestSuite + explicitly?</b> + </p> + <p> + <i>(Submitted by: Bill de hora)</i> + </p> + <p> + There are a number of ways to do this: + </p> + <ol> + <li> + <p> + In Ant, use the <code>junit</code> task and + the <code>batchtest</code> element: + </p> + <div> + <pre><code> +<junit printsummary="yes" haltonfailure="yes"> + ... + <batchtest fork="yes"> + <fileset dir="${src.dir}"> + <include name="**/*Test.java" /> + <include name="**/Test*.java" /> + </fileset> + </batchtest> +</junit> + </code></pre> + </div> + <p> + Idiomatic naming patterns for unit tests + are <code>Test*.java</code> and <code>*Test.java</code>. + Documentation and examples are at <a + href="http://ant.apache.org/manual/OptionalTasks/junit.html">http://ant.apache.org/manual/OptionalTasks/junit.html</a>. + </p> + </li> + <li> + <p> + Use the <code>DirectorySuiteBuilder</code> + and <code>ArchiveSuiteBuilder</code> (for jar/zip files) + classes provided by JUnit-addons project: + </p> + <div> + <blockquote><pre> +DirectorySuiteBuilder builder = new DirectorySuiteBuilder(); +builder.setSuffix("Test"); +Test suite = builer.suite("/home/project/myproject/tests"); + </pre></blockquote> + </div> + <p> + Documentation and examples are at <a + href="http://junit-addons.sourceforge.net/">http://junit-addons.sourceforge.net</a>. + </p> + </li> + <li> + <p> + Write your own custom suite builder. + </p> + <p> + Have your test classes implement an interface and write a + treewalker to load each class in a directory, inspect the + class, and add any classes that implement the interface to a + TestSuite. + </p> + <p> + You might only want to do this if you are <b>very</b> + uncomfortable with using a naming convention for test + classes. Aside from being slow for larger suites, ultimately + it's arguable whether it's more effort to follow a naming + convention that have test classes implement an interface! + </p> + <p> + An example of this approach is at + <a href="http://www.javaworld.com/javaworld/jw-12-2000/jw-1221-junit_p.html">http://www.javaworld.com/javaworld/jw-12-2000/jw-1221-junit_p.html</a>. + </p> + </li> + </ol> + </li> +</ol> + +<!-- + + Best Practices + +--> +<div class="header"> +<a name="best">Best Practices</a> +</div> +<ol> + <li> + <p> + <b><a name="best_1"></a>When should tests be written?</b> + </p> + <p> + Tests should be written before the code. Test-first programming + is practiced by only writing new code when an automated test is + failing. + </p> + <p> + Good tests tell you how to best design the system for its + intended use. They effectively communicate in an executable + format how to use the software. They also prevent tendencies to + over-build the system based on speculation. When all the tests + pass, you know you're done! + </p> + <p> + Whenever a customer test fails or a bug is reported, first write + the necessary unit test(s) to expose the bug(s), <em>then</em> + fix them. This makes it almost impossible for that particular + bug to resurface later. + </p> + <p> + Test-driven development is a lot more fun than writing tests + after the code seems to be working. Give it a try! + </p> + </li> + <li> + <p> + <b><a name="best_2"></a>Do I have to write a test for + everything?</b> + </p> + <p> + No, just test everything that could reasonably break. + </p> + <p> + Be practical and maximize your testing investment. Remember + that investments in testing are equal investments in design. If + defects aren't being reported and your design responds well to + change, then you're probably testing enough. If you're spending + a lot of time fixing defects and your design is difficult to + grow, you should write more tests. + </p> + <p> + If something is difficult to test, it's usually an opportunity + for a design improvement. Look to improve the design so that + it's easier to test, and by doing so a better design will + usually emerge. + </p> + </li> + <li> + <p> + <b><a name="best_3"></a>How simple is 'too simple to break'?</b> + </p> + <p> + <i>(Submitted by: J. B. Rainsberger)</i> + </p> + <p> + The general philosophy is this: if it can't break <em>on its + own</em>, it's too simple to break. + </p> + <p> + First example is the <code>getX()</code> method. Suppose + the <code>getX()</code> method only answers the value of an + instance variable. In that case, <code>getX()</code> cannot + break unless either the compiler or the interpreter is also + broken. For that reason, don't test <code>getX()</code>; there + is no benefit. The same is true of the <code>setX()</code> + method, although if your <code>setX()</code> method does any + parameter validation or has any side effects, you likely need to + test it. + </p> + <p> + Next example: suppose you have written a method that does + nothing but forward parameters into a method called on another + object. That method is too simple to break. + </p> + <div> + <blockquote><pre> +public void myMethod(final int a, final String b) { + myCollaborator.anotherMethod(a, b); +} + </pre></blockquote> + </div> + <p> + <code>myMethod</code> cannot possibly break because it does nothing: it + forwards its input to another object and that's all. + </p> + <p> + The only precondition for this method is "myCollaborator != + null", but that is generally the responsibility of the + constructor, and not of myMethod. If you are concerned, add a + test to verify that myCollaborator is always set to something + non-null by every constructor. + </p> + <p> + The only way myMethod could break would be + if <code>myCollaborator.anotherMethod()</code> were broken. In + that case, test <code>myCollaborator</code>, and not the current + class. + </p> + <p> + It is true that adding tests for even these simple methods + guards against the possibility that someone refactors and makes + the methods "not-so-simple" anymore. In that case, though, the + refactorer needs to be aware that the method is now complex + enough to break, and should write tests for it -- and preferably + before the refactoring. + </p> + <p> + Another example: suppose you have a JSP and, like a good + programmer, you have removed all business logic from it. All it + does is provide a layout for a number of JavaBeans and never + does anything that could change the value of any object. That + JSP is too simple to break, and since JSPs are notoriously + annoying to test, you should strive to make all your JSPs too + simple to break. + </p> + <p> + Here's the way testing goes: + </p> + <div> + <blockquote><pre> +becomeTimidAndTestEverything +while writingTheSameThingOverAndOverAgain + becomeMoreAggressive + writeFewerTests + writeTestsForMoreInterestingCases + if getBurnedByStupidDefect + feelStupid + becomeTimidAndTestEverything + end +end + </pre></blockquote> + </div> + <p> + The loop, as you can see, never terminates. + </p> + </li> + <li> + <p> + <b><a name="best_4"></a>How often should I run my tests?</b> + </p> + <p> + Run all your unit tests as often as possible, ideally every time + the code is changed. Make sure all your unit tests always run + at 100%. Frequent testing gives you confidence that your + changes didn't break anything and generally lowers the stress of + programming in the dark. + </p> + <p> + For larger systems, you may just run specific test suites that + are relevant to the code you're working on. + </p> + <p> + Run all your acceptance, integration, stress, and unit tests at + least once per day (or night). + </p> + <p> + If you're using Eclipse, be sure to check out David Saff's + <a href="http://pag.csail.mit.edu/continuoustesting/">continuous + testing plug-in</a>. + </p> + </li> + <li> + <p> + <b><a name="best_5"></a>What do I do when a defect is reported?</b> + </p> + <p> + Test-driven development generally lowers the defect density of + software. But we're all fallible, so sometimes a defect will + slip through. When this happens, write a failing test that + exposes the defect. When the test passes, you know the defect + is fixed! + </p> + <p> + Don't forget to use this as a learning opportunity. Perhaps the + defect could have been prevented by being more aggressive about + testing everything that could reasonably break. + </p> + </li> + <li> + <p> + <b><a name="best_6"></a>Why not just use <code>System.out.println()</code>?</b> + </p> + <p> + Inserting debug statements into code is a low-tech method for + debugging it. It usually requires that output be scanned + manually every time the program is run to ensure that the code + is doing what's expected. + </p> + <p> + It generally takes less time in the long run to codify + expectations in the form of an automated JUnit test that retains + its value over time. If it's difficult to write a test to + assert expectations, the tests may be telling you that shorter + and more cohesive methods would improve your design. + </p> + </li> + <li> + <p> + <b><a name="best_7"></a>Why not just use a debugger?</b> + </p> + <p> + Debuggers are commonly used to step through code and inspect + that the variables along the way contain the expected values. + But stepping through a program in a debugger is a manual process + that requires tedious visual inspections. In essence, the + debugging session is nothing more than a manual check of + expected vs. actual results. Moreover, every time the program + changes we must manually step back through the program in the + debugger to ensure that nothing broke. + </p> + <p> + It generally takes less time to codify expectations in the form + of an automated JUnit test that retains its value over time. If + it's difficult to write a test to assert expected values, the + tests may be telling you that shorter and more cohesive methods + would improve your design. + </p> + </li> +</ol> + +<!-- + + Miscellaneous + +--> +<div class="header"> +<a name="misc">Miscellaneous</a> +</div> +<ol> + <li> + <p> + <b><a name="misc_1"></a>How do I integrate JUnit with my IDE?</b> + </p> + <p> + The JUnit home page maintains a list of <a + href="http://www.junit.org/news/ide/index.htm">IDE integration + instructions</a>. + </p> + </li> + <li> + <p> + <b><a name="misc_2"></a>How do I launch a debugger when a test fails?</b> + </p> + <p> + Start the <code>TestRunner</code> under the debugger and + configure the debugger so that it catches + the <code>junit.framework.AssertionFailedError</code>. + </p> + <p> + How you configure this depends on the debugger you prefer to + use. Most Java debuggers provide support to stop the program + when a specific exception is raised. + </p> + <p> + Notice that this will only launch the debugger when an expected + failure occurs. + </p> + </li> + <li> + <p> + <b><a name="misc_3"></a>Where can I find unit testing frameworks + similar to JUnit for other languages?</b> + </p> + <p> + XProgramming.com maintains a complete list of available <a + href="http://www.xprogramming.com/software.htm">xUnit testing + frameworks</a>. + </p> + </li> +</ol> + +<br/> + +<div align="right"> + <a href="http://validator.w3.org/check?uri=referer"> + <img src="http://www.w3.org/Icons/valid-xhtml10" + alt="Valid XHTML 1.0!" height="31" width="88" /></a> +</div> + +</body> +</html> diff --git a/junit4/doc/homepage.html b/junit4/doc/homepage.html new file mode 100644 index 0000000..ff2a027 --- /dev/null +++ b/junit4/doc/homepage.html @@ -0,0 +1,115 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<!-- saved from url=(0029)http://junit.sourceforge.net/ --> +<HTML><HEAD><TITLE>JUnit</TITLE> +<META http-equiv=Content-Type content="text/html; charset=iso-8859-1"> +<META content="MSHTML 6.00.2712.300" name=GENERATOR> +<META content="Erich Gamma" name=Author></HEAD> +<BODY> +<H1><B><FONT color=#00cc00>J</FONT><FONT color=#ff0000>U</FONT><FONT +color=#000000>nit </FONT></B></H1> +<P>JUnit is a simple framework to write repeatable tests. It is an instance of +the xUnit architecture for unit testing frameworks. +<UL> + <LI><A href="http://junit.sourceforge.net/#Getting">Getting Started</A> + + <LI><A href="http://junit.sourceforge.net/#Documentation">Documentation</A> + <LI><A href="http://junit.sourceforge.net/#Related">JUnit related + sites/projects</A> </LI> + <LI><A href="http://junit.sourceforge.net/#Mail">Mailing Lists</A></LI> + <LI><A href="http://junit.sourceforge.net/#Developer">Get Involved</A></LI> +</UL> + +<h2> +<a NAME="Getting"></a>Getting Started</h2> + +To get started with unit testing and JUnit read the article: +<a href="doc/cookbook/cookbook.htm">JUnit Cookbook</a>. +<br>This article describes basic test writing using JUnit 4. +<p>You find additional samples in the org.junit.samples package: +<ul> +<li> +SimpleTest.java - some simple test cases</li> + +<li> +VectorTest.java - test cases for java.util.Vector</li> +</ul> +<P>JUnit 4.x only comes with a textual TestRunner. For graphical feedback, +most major IDE's support +JUnit 4. If necessary, you can run JUnit 4 tests in a JUnit 3 +environment by adding the following method to each test class: +<pre> +public static Test suite() { + return new JUnit4TestAdapter(ThisClass.class); +} + +</pre> + +<h2> +<a NAME="Documentation"></a>Documentation</h2> + +<blockquote><a href="doc/cookbook/cookbook.htm">JUnit Cookbook</a> +<br> A cookbook for implementing tests with JUnit. +<br><a href="javadoc_40/index.html">Javadoc</a> +<br> API documentation generated with javadoc. +<br><a href="doc/faq/faq.htm">Frequently asked questions</a> +<br> Some frequently asked questions about using JUnit. + +<br><a href="README.html">Release notes</a> +<br> Latest JUnit release notes +<br><a href="cpl-v10.html">License</a> +<br> The terms of the common public license used for JUnit.<br> +</blockquote> +The following documents still describe JUnit 3.8. +<blockquote> +<br><a href="junit3.8.1/index.html">The JUnit 3.8 version of this homepage</a> +<br><a href="doc/testinfected/testing.htm">Test Infected - Programmers +Love Writing Tests</a> +<br> An article demonstrating the development process +with JUnit. + +<br><a href="doc/cookstour/cookstour.htm">JUnit - A cooks tour</a> +</blockquote> + +<H2><A name=Related></A>JUnit Related Projects/Sites</H2> +<UL> + <LI><A href="http://www.junit.org/">junit.org</A> - a site for software + developers using JUnit. It provides instructions for how to integrate JUnit + with development tools like JBuilder and VisualAge/Java. As well as articles + about and extensions to JUnit.</LI> + <LI><A href="http://www.xprogramming.com/software.htm">XProgramming.com</A> - + various implementations of the xUnit testing framework architecture. </LI> + +</UL> +<H2><A name=Mail></A>Mailing Lists</H2> +There are three junit mailing lists: +<UL> + <LI>JUnit announce: junit-announce@lists.sourceforge.net <A + href="http://lists.sourceforge.net/lists/listinfo/junit-announce">Archives/Subscribe/Unsubscribe</A></LI> + <LI>JUnit users list: junit@yahoogroups.com <A + href="http://groups.yahoo.com/group/junit/">Archives/Subscribe/Unsubscribe</A></LI> + <LI>JUnit developer list: junit-devel@lists.sourceforge.net <A + href="http://lists.sourceforge.net/lists/listinfo/junit-devel">Archives/Subscribe/Unsubscribe</A></LI> + + </UL> + + <H2><A name=Developer></A>Get Involved</H2> + JUnit celebrates programmers testing their own software. As a result + bugs, patches, and feature requests which include JUnit TestCases have a + better + chance of being addressed than those without. + + <br/> + JUnit is forged on + Sourceforge please use the tools <A + href="http://sf.net/projects/junit">provided</A> for your submissions. + + <br/> + JUnit source code is now hosted on <a href="http://github.com/KentBeck/junit">GitHub</a>. + +<hr WIDTH="100%"> +<font size="1"> +hosted by </font> <A href="http://sourceforge.net"><IMG src="http://sourceforge.net/sflogo.php?group_id=15278" width="88" height="31" +border="0" alt="SourceForge Logo"></A> +</font> + +</BODY></HTML> diff --git a/junit4/doc/index.htm b/junit4/doc/index.htm new file mode 100644 index 0000000..dd19ff3 --- /dev/null +++ b/junit4/doc/index.htm @@ -0,0 +1,21 @@ +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <meta name="Author" content="Erich Gamma"> + <title>JUnit Documentation</title> +</head> +<body> + +<h1> +<font color="#33FF33">J</font><font color="#CC0000">U</font>nit Documentation</h1> + +<p> +Kent Beck, Erich Gamma, David Saff</p> + +<hr WIDTH="100%"> +We have just begun documenting the new JUnit 4 architecture. The
<a href="cookbook/cookbook.htm">cookbook</a> has already been updated. You can find the javadoc <a href="../javadoc/index.html">here</a>. +The JUnit home page is <a href="http://www.junit.org">here</a>. +<hr WIDTH="100%"> +</body> +</html> diff --git a/junit4/doc/markdown.sh b/junit4/doc/markdown.sh new file mode 100644 index 0000000..e235b63 --- /dev/null +++ b/junit4/doc/markdown.sh @@ -0,0 +1 @@ +~/bin/Markdown.pl ReleaseNotes4.8.txt >ReleaseNotes4.8.html
\ No newline at end of file diff --git a/junit4/doc/testinfected/IMG00001.GIF b/junit4/doc/testinfected/IMG00001.GIF Binary files differnew file mode 100644 index 0000000..ca491c1 --- /dev/null +++ b/junit4/doc/testinfected/IMG00001.GIF diff --git a/junit4/doc/testinfected/IMG00002.GIF b/junit4/doc/testinfected/IMG00002.GIF Binary files differnew file mode 100644 index 0000000..2fc614f --- /dev/null +++ b/junit4/doc/testinfected/IMG00002.GIF diff --git a/junit4/doc/testinfected/IMG00003.GIF b/junit4/doc/testinfected/IMG00003.GIF Binary files differnew file mode 100644 index 0000000..2695af3 --- /dev/null +++ b/junit4/doc/testinfected/IMG00003.GIF diff --git a/junit4/doc/testinfected/logo.gif b/junit4/doc/testinfected/logo.gif Binary files differnew file mode 100644 index 0000000..d0e1547 --- /dev/null +++ b/junit4/doc/testinfected/logo.gif diff --git a/junit4/doc/testinfected/testing.htm b/junit4/doc/testinfected/testing.htm new file mode 100644 index 0000000..d11c11c --- /dev/null +++ b/junit4/doc/testinfected/testing.htm @@ -0,0 +1,617 @@ +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <meta name="GENERATOR" content="Mozilla/4.75 [en] (Windows NT 5.0; U) [Netscape]"> + <title>Test Infected: </title> +</head> +<body> + +<h1> +<b><font color="#00CC00">J</font><font color="#FF0000">U</font><font color="#000000">nit</font> <font size=+3>Test +Infected: Programmers Love Writing Tests</font></b></h1> +<br>Note: this article describes JUnit 3.8.x. + +<hr WIDTH="100%"> +<p>Testing is not closely integrated with development. This prevents you +from measuring the progress of development- you can't tell when something +starts working or when something stops working. Using <i>JUnit</i> you +can cheaply and incrementally build a test suite that will help you measure +your progress, spot unintended side effects, and focus your development +efforts. +<h1> +Contents</h1> + +<ul> +<li> +<a href="#TheProblem">The Problem</a></li> + +<li> +<a href="#Example">Example</a></li> + +<li> +<a href="#TestingPractices">Testing Practices</a></li> + +<li> +<a href="#Conclusion">Conclusions</a></li> +</ul> + +<h1> +<a NAME="TheProblem"></a>The Problem</h1> +Every programmer knows they should write tests for their code. Few do. +The universal response to "Why not?" is "I'm in too much of a hurry." This +quickly becomes a vicious cycle- the more pressure you feel, the fewer +tests you write. The fewer tests you write, the less productive you are +and the less stable your code becomes. The less productive and accurate +you are, the more pressure you feel. +<p>Programmers burn out from just such cycles. Breaking out requires an +outside influence. We found the outside influence we needed in a simple +testing framework that lets us do a little testing that makes a big difference. +<p>The best way to convince you of the value of writing your own tests +would be to sit down with you and do a bit of development. Along the way, +we would encounter new bugs, catch them with tests, fix them, have them +come back, fix them again, and so on. You would see the value of the immediate +feedback you get from writing and saving and rerunning your own unit tests. +<p>Unfortunately, this is an article, not an office overlooking charming +old-town Zürich, with the bustle of medieval commerce outside and +the thump of techno from the record store downstairs, so we'll have to +simulate the process of development. We'll write a simple program and its +tests, and show you the results of running the tests. This way you can +get a feel for the process we use and advocate without having to pay for +our presence. +<h1> +<a NAME="Example"></a>Example</h1> +As you read, pay attention to the interplay of the code and the tests. +The style here is to write a few lines of code, then a test that should +run, or even better, to write a test that won't run, then write the code +that will make it run. +<p>The program we write will solve the problem of representing arithmetic +with multiple currencies. Arithmetic between single currencies is trivial, +you can just add the two amounts. Simple numbers suffice. You can ignore +the presence of currencies altogether. +<p>Things get more interesting once multiple currencies are involved. You +cannot just convert one currency into another for doing arithmetic since +there is no single conversion rate- you may need to compare the value of +a portfolio at yesterday's rate and today's rate. +<p>Let's start simple and define a class <a href="#classMoney">Money</a> +to represent a value in a single currency. We represent the amount by a +simple int. To get full accuracy you would probably use double or java.math.BigDecimal +to store arbitrary-precision signed decimal numbers. We represent a currency +as a string holding the ISO three letter abbreviation (USD, CHF, etc.). +In more complex implementations, currency might deserve its own object. +<pre><a NAME="classMoney"></a><tt>class Money { + private int fAmount; + private String fCurrency;</tt></pre> + +<pre><tt> public Money(int amount, String currency) { + fAmount= amount; + fCurrency= currency; + } + + public int amount() { + return fAmount; + } + + public String currency() { + return fCurrency; + } +}</tt></pre> +When<font size=-1> </font>you add two Moneys of the same currency, the +resulting Money has as its amount the sum of the other two amounts. +<pre><a NAME="MoneyAdd"></a><tt>public Money add(Money m) { + return new Money(amount()+m.amount(), currency()); +}</tt></pre> +Now, instead of just coding on, we want to get immediate feedback and practice +"code a little, test a little, code a little, test a little". To implement +our tests we use the JUnit framework. To write tests you need to get the +<a href="http://sourceforge.net/projects/junit/">latest +copy</a> JUnit (or write your own equivalent- it's not so much work). +<p>JUnit defines how to structure your test cases and provides the tools +to run them. You implement a test in a subclass of TestCase. To test our +Money implementation we therefore define <a href="#class MoneyTest">MoneyTest</a> +as a subclass of TestCase. In Java, classes are contained in packages and +we have to decide where to put MoneyTest. Our current practice is to put +MoneyTest in the same package as the classes under test. In this way a +test case has access to the package private methods. We add a test method +testSimpleAdd, that will exercise the simple version of <a href="#MoneyAdd">Money.add()</a> +above. A JUnit test method is an ordinary method without any parameters. +<pre><a NAME="class MoneyTest"></a><tt>public class MoneyTest extends TestCase { + //… + public void testSimpleAdd() { + Money m12CHF= new Money(12, "CHF"); // <a NAME="MoneyTest1"></a>(1) + Money m14CHF= new Money(14, "CHF"); + Money expected= new Money(26, "CHF"); + Money result= m12CHF.add(m14CHF); // <a NAME="MoneyTest2"></a>(2) + Assert.assertTrue(expected.equals(result)); // <a NAME="MoneyTest3"></a>(3) + } +}</tt></pre> +The testSimpleAdd() test case consists of: +<ol> +<li> +<a href="#MoneyTest1">Code</a> which creates the objects we will interact +with during the test. This testing context is commonly referred to as a +test's<i> fixture</i>. All we need for the testSimpleAdd test are some +Money objects.</li> + +<li> +<a href="#MoneyTest2">Code</a> which exercises the objects in the fixture.</li> + +<li> +<a href="#MoneyTest3">Code</a> which verifies the result.</li> +</ol> +Before we can verify the result we have to digress a little since we need +a way to test that two Money objects are equal. The Java idiom to do so +is to override the method <i>equals</i> defined in Object. Before we implement +equals let's a write a test for equals in MoneyTest. +<pre><tt>public void testEquals() { + Money m12CHF= new Money(12, "CHF"); + Money m14CHF= new Money(14, "CHF"); + + Assert.assertTrue(!m12CHF.equals(null)); + Assert.assertEquals(m12CHF, m12CHF); + Assert.assertEquals(m12CHF, new Money(12, "CHF")); // <a NAME="TestEquals1"></a>(1) + Assert.assertTrue(!m12CHF.equals(m14CHF)); +}</tt></pre> +The equals method in Object returns true when both objects are the same. +However, Money is a <i>value object</i>. Two Monies are considered equal +if they have the same currency and value. To test this property we have +added a test <a href="#TestEquals1">(1)</a> to verify that Monies are equal +when they have the same value but are not the same object. +<p>Next let's write the equals method in Money: +<pre><tt>public boolean equals(Object anObject) { + if (anObject instanceof Money) { + Money aMoney= (Money)anObject; + return aMoney.currency().equals(currency()) + && amount() == aMoney.amount(); + } + return false; +}</tt></pre> +Since equals can receive any kind of object as its argument we first have +to check its type before we cast it as a Money. As an aside, it is a recommended +practice to also override the method hashCode whenever you override method +equals. However, we want to get back to our test case. +<p>With an equals method in hand we can verify the outcome of testSimpleAdd. +In JUnit you do so by a calling +<A HREF="../../javadoc/junit/framework/Assert.html#assertTrue(boolean)">Assert.assertTrue</a>, +which triggers a failure that is recorded by JUnit when the argument isn't +true. Since assertions for equality are very common, there is also +an Assert.assertEquals convenience method. In addition to testing for equality +with equals, it reports the printed value of the two objects in the case they +differ. This lets us immediately see why a test failed in a JUnit test +result report. The value a string representation created by +the toString converter method. +There are <a href="../../javadoc/junit/framework/Assert.html"> +other asertXXXX variants</a> not discussed here. +<p>Now that we have implemented two test cases we notice some code duplication +for setting-up the tests. It would be nice to reuse some of this test set-up +code. In other words, we would like to have a common fixture for running +the tests. With JUnit you can do so by storing the fixture's objects in +instance variables of your +<a href="../../javadoc/junit/framework/TestCase.html">TestCase</a> +subclass and initialize them by overridding +the setUp method. The symmetric operation to setUp is tearDown which you +can override to clean up the test fixture at the end of a test. Each test +runs in its own fixture and JUnit calls setUp and tearDown for each test +so that there can be no side effects among test runs. +<pre><tt>public class MoneyTest extends TestCase { + private Money f12CHF; + private Money f14CHF; + + protected void setUp() { + f12CHF= new Money(12, "CHF"); + f14CHF= new Money(14, "CHF"); + } +}</tt></pre> +We can rewrite the two test case methods, removing the common setup code: +<pre><tt>public void testEquals() { + Assert.assertTrue(!f12CHF.equals(null)); + Assert.assertEquals(f12CHF, f12CHF); + Assert.assertEquals(f12CHF, new Money(12, "CHF")); + Assert.assertTrue(!f12CHF.equals(f14CHF)); +} + +public void testSimpleAdd() { + Money expected= new Money(26, "CHF"); + Money result= f12CHF.add(f14CHF); + Assert.assertTrue(expected.equals(result)); +}</tt></pre> +Two additional steps are needed to run the two test cases: +<ol> +<li> +define how to run an individual test case,</li> + +<li> +define how to run a <i>test suite</i>.</li> +</ol> +JUnit supports two ways of running single tests: +<ul> +<li> +static</li> + +<li> +dynamic</li> +</ul> +In the static way you override the runTest method inherited from TestCase +and call the desired test case. A convenient way to do this is with an +anonymous inner class. Note that each test must be given a name, so you +can identify it if it fails. +<pre><tt>TestCase test= new MoneyTest("simple add") { + public void runTest() { + testSimpleAdd(); + } +};</tt></pre> +A template method<a href="#Gamma, E., et al. Design Patterns: Elements of">[1]</a> +in the superclass will make sure runTest is executed when the time comes. +<p>The dynamic way to create a test case to be run uses reflection to implement +runTest. It assumes the name of the test is the name of the test case method +to invoke. It dynamically finds and invokes the test method. To invoke +the testSimpleAdd test we therefore construct a MoneyTest as shown below: +<pre><tt>TestCase test= new MoneyTest("testSimpleAdd");</tt></pre> +The dynamic way is more compact to write but it is less static type safe. +An error in the name of the test case goes unnoticed until you run it and +get a NoSuchMethodException. Since both approaches have advantages, we +decided to leave the choice of which to use up to you. +<p>As the last step to getting both test cases to run together, we have +to define a test suite. In JUnit this requires the definition of a static +method called suite. The suite method is like a main method that is specialized +to run tests. Inside suite you add the tests to be run to a +<a href="../../javadoc/junit/framework/TestSuite.html">TestSuite</a> object +and return it. A TestSuite can run a collection of tests. TestSuite and +TestCase both implement an interface called Test which defines the methods +to run a test. This enables the creation of test suites by composing arbitrary +TestCases and TestSuites. In short TestSuite is a Composite <a href="#Gamma, E., et al. Design Patterns: Elements of">[1].</a> +The code below illustrates the creation of a test suite with the dynamic +way to run a test. +<pre><tt>public static Test suite() { + TestSuite suite= new TestSuite(); + suite.addTest(new MoneyTest("testEquals")); + suite.addTest(new MoneyTest("testSimpleAdd")); + return suite; +}</tt></pre> +Since JUnit 2.0 there is an even simpler dynamic way. You only pass the +class with the tests to a TestSuite and it extracts the test methods automatically. +<p><tt>public static Test suite() {<br> + return new TestSuite(MoneyTest.class);<br> +}</tt><tt></tt> +<p>Here is the corresponding code using the static way. +<pre><tt>public static Test suite() { + TestSuite suite= new TestSuite(); + suite.addTest( + new MoneyTest("money equals") { + protected void runTest() { testEquals(); } + } + ); + + suite.addTest( + new MoneyTest("simple add") { + protected void runTest() { testSimpleAdd(); } + } + ); + return suite; +}</tt></pre> +Now we are ready to run our tests. JUnit comes with a graphical interface +to run tests. Type the name of your test class in the field at the top +of the window. Press the Run button. While the test is run JUnit shows +its progress with a progress bar below the input field. The bar is initially +green but turns into red as soon as there is an unsuccessful test. Failed +tests are shown in a list at the bottom. <a href="#Figure1">Figure 1</a> +shows the TestRunner window after we run our trivial test suite. +<center><img SRC="IMG00001.GIF" > +<br><a NAME="Figure1"></a><b>Figure 1</b>: A Successful Run</center> + +<p>After having verified that the simple currency case works we move on +to multiple currencies. As mentioned above the problem of mixed currency +arithmetic is that there isn't a single exchange rate. To avoid this problem +we introduce a MoneyBag which defers exchange rate conversions. For example +adding 12 Swiss Francs to 14 US Dollars is represented as a bag containing +the two Monies 12 CHF and 14 USD. Adding another 10 Swiss francs gives +a bag with 22 CHF and 14 USD. We can later evaluate a MoneyBag with different +exchange rates. +<p>A MoneyBag is represented as a list of Monies and provides different +constructors to create a MoneyBag. Note, that the constructors are package +private since MoneyBags are created behind the scenes when doing currency +arithmetic. +<pre><tt>class MoneyBag { + private Vector fMonies= new Vector(); + + MoneyBag(Money m1, Money m2) { + appendMoney(m1); + appendMoney(m2); + } + + MoneyBag(Money bag[]) { + for (int i= 0; i < bag.length; i++) + appendMoney(bag[i]); + } +}</tt></pre> +The method appendMoney is an internal helper method that adds a Money to +the list of Moneys and takes care of consolidating Monies with the same +currency. MoneyBag also needs an equals method together with a corresponding +test. We skip the implementation of equals and only show the testBagEquals +method. In a first step we extend the fixture to include two MoneyBags. +<pre><tt>protected void setUp() { + f12CHF= new Money(12, "CHF"); + f14CHF= new Money(14, "CHF"); + f7USD= new Money( 7, "USD"); + f21USD= new Money(21, "USD"); + fMB1= new MoneyBag(f12CHF, f7USD); + fMB2= new MoneyBag(f14CHF, f21USD); +}</tt></pre> +With this fixture the testBagEquals test case becomes: +<pre><tt>public void testBagEquals() { + Assert.assertTrue(!fMB1.equals(null)); + Assert.assertEquals(fMB1, fMB1); + Assert.assertTrue(!fMB1.equals(f12CHF)); + Assert.assertTrue(!f12CHF.equals(fMB1)); + Assert.assertTrue(!fMB1.equals(fMB2)); +}</tt></pre> +Following "code a little, test a little" we run our extended test with +JUnit and verify that we are still doing fine. With MoneyBag in hand, we +can now fix the add method in Money. +<pre><tt>public Money add(Money m) { + if (m.currency().equals(currency()) ) + return new Money(amount()+m.amount(), currency()); + return new MoneyBag(this, m); +}</tt></pre> +As defined above this method will not compile since it expects a Money +and not a MoneyBag as its return value. With the introduction of MoneyBag +there are now two representations for Moneys which we would like to hide +from the client code. To do so we introduce an interface IMoney that both +representations implement. Here is the IMoney interface: +<pre><tt>interface IMoney { + public abstract IMoney add(IMoney aMoney); + //… +}</tt></pre> +To fully hide the different representations from the client we have to +support arithmetic between all combinations of Moneys with MoneyBags. Before +we code on, we therefore define a couple more test cases. The expected +MoneyBag results use the convenience constructor shown above, initializing +a MoneyBag from an array. +<pre><tt>public void testMixedSimpleAdd() { + // [12 CHF] + [7 USD] == {[12 CHF][7 USD]} + Money bag[]= { f12CHF, f7USD }; + MoneyBag expected= new MoneyBag(bag); + Assert.assertEquals(expected, f12CHF.add(f7USD)); +}</tt></pre> +The other tests follow the same pattern: +<menu> +<li> +testBagSimpleAdd - to add a MoneyBag to a simple Money</li> + +<li> +testSimpleBagAdd - to add a simple Money to a MoneyBag</li> + +<li> +testBagBagAdd - to add two MoneyBags</li> +</menu> +Next, we extend our test suite accordingly: +<pre><tt>public static Test suite() { + TestSuite suite= new TestSuite(); + suite.addTest(new MoneyTest("testMoneyEquals")); + suite.addTest(new MoneyTest("testBagEquals")); + suite.addTest(new MoneyTest("testSimpleAdd")); + suite.addTest(new MoneyTest("testMixedSimpleAdd")); + suite.addTest(new MoneyTest("testBagSimpleAdd")); + suite.addTest(new MoneyTest("testSimpleBagAdd")); + suite.addTest(new MoneyTest("testBagBagAdd")); + return suite; +}</tt></pre> +Having defined the test cases we can start to implement them. The implementation +challenge here is dealing with all the different combinations of Money +with MoneyBag. Double dispatch <a href="#Beck, K. Smalltalk Best Practice Patterns,">[2]</a> +is an elegant way to solve this problem. The idea behind double dispatch +is to use an additional call to discover the kind of argument we are dealing +with. We call a method on the argument with the name of the original method +followed by the class name of the receiver. The add method in Money and +MoneyBag becomes: +<pre><tt>class Money implements IMoney { + public IMoney add(IMoney m) { + return m.addMoney(this); + } + //… +}</tt></pre> + +<pre><tt>class MoneyBag implements IMoney { + public IMoney add(IMoney m) { + return m.addMoneyBag(this); + } + //… +}</tt></pre> +In order to get this to compile we need to extend the interface of IMoney +with the two helper methods: +<pre><tt>interface IMoney { +//… + IMoney addMoney(Money aMoney); + IMoney addMoneyBag(MoneyBag aMoneyBag); +}</tt></pre> +To complete the implementation of double dispatch, we have to implement +these methods in Money and MoneyBag. This is the implementation in Money. +<pre><tt>public IMoney addMoney(Money m) { + if (m.currency().equals(currency()) ) + return new Money(amount()+m.amount(), currency()); + return new MoneyBag(this, m); +} + +public IMoney addMoneyBag(MoneyBag s) { + return s.addMoney(this); +}</tt></pre> +Here is the implemenation in MoneyBag which assumes additional constructors +to create a MoneyBag from a Money and a MoneyBag and from two MoneyBags. +<pre><tt>public IMoney addMoney(Money m) { + return new MoneyBag(m, this); +} + +public IMoney addMoneyBag(MoneyBag s) { + return new MoneyBag(s, this); +}</tt></pre> +We run the tests, and they pass. However, while reflecting on the implementation +we discover another interesting case. What happens when as the result of +an addition a MoneyBag turns into a bag with only one Money? For example, +adding -12 CHF to a Moneybag holding 7 USD and 12 CHF results in a bag +with just 7 USD. Obviously, such a bag should be equal with a single Money +of 7 USD. To verify the problem let's implement a test case and run it. +<pre><tt>public void testSimplify() { + // {[12 CHF][7 USD]} + [-12 CHF] == [7 USD] + Money expected= new Money(7, "USD"); + Assert.assertEquals(expected, fMB1.add(new Money(-12, "CHF"))); +}</tt></pre> +When you are developing in this style you will often have a thought and +turn immediately to writing a test, rather than going straight to the code. +<p>It comes to no surprise that our test run ends with a red progress bar +indicating the failure. So we fix the code in MoneyBag to get back to a +green state. +<pre><tt>public IMoney addMoney(Money m) { + return (new MoneyBag(m, this)).simplify(); +} + +public IMoney addMoneyBag(MoneyBag s) { + return (new MoneyBag(s, this)).simplify(); +} + +private IMoney simplify() { + if (fMonies.size() == 1) + return (IMoney)fMonies.firstElement() + return this; +}</tt></pre> +Now we run our tests again and voila we end up with green. +<p>The code above solves only a small portion of the multi-currency arithmetic +problem. We have to represent different exchange rates, print formatting, +and the other arithmetic operations, and do it all with reasonable speed. +However, we hope you can see how you could develop the rest of the objects +one test at a time- a little test, a little code, a little test, a little +code. +<p>In particular, review how in the development above: +<ul> +<li> +We wrote the first test, testSimpleAdd, immediately after we had written +add(). In general, your development will go much smoother if you write +tests a little at a time as you develop. It is at the moment that you are +coding that you are imagining how that code will work. That's the perfect +time to capture your thoughts in a test.</li> + +<li> +We refactored the existing tests, testSimpleAdd and testEqual, as soon +as we introduced the common setUp code. Test code is just like model code +in working best if it is factored well. When you see you have the same +test code in two places, try to find a way to refactor it so it only appears +once.</li> + +<li> +We created a suite method, then extended it when we applied Double Dispatch. +Keeping old tests running is just as important as making new ones run. +The ideal is to always run all of your tests. Sometimes that will be too +slow to do 10 times an hour. Make sure you run all of your tests at least +daily.</li> + +<li> +We created a new test immediately when we thought of the requirement that +a one element MoneyBag should just return its element. It can be difficult +to learn to switch gears like this, but we have found it valuable. When +you are struck by an idea of what your system should do, defer thinking +about the implementation. Instead, first write the test. Then run it (you +never know, it might already work). Then work on the implementation.</li> +</ul> + +<h1> +<a NAME="TestingPractices"></a>Testing Practices</h1> +Martin Fowler makes this easy for you. He says, "Whenever you are tempted +to type something into a print statement or a debugger expression, write +it as a test instead." At first you will find that you have to create a +new fixtures all the time, and testing will seem to slow you down a little. +Soon, however, you will begin reusing your library of fixtures and new +tests will usually be as simple as adding a method to an existing TestCase +subclass. +<p>You can always write more tests. However, you will quickly find that +only a fraction of the tests you can imagine are actually useful. What +you want is to write tests that fail even though you think they should +work, or tests that succeed even though you think they should fail. Another +way to think of it is in cost/benefit terms. You want to write tests that +will pay you back with information. +<p>Here are a couple of the times that you will receive a reasonable return +on your testing investment: +<ul> +<li> +During Development- When you need to add new functionality to the system, +write the tests first. Then, you will be done developing when the test +runs.</li> + +<li> +During Debugging- When someone discovers a defect in your code, first write +a test that will succeed if the code is working. Then debug until the test +succeeds.</li> +</ul> +One word of caution about your tests. Once you get them running, make sure +they stay running. There is a huge difference between having your suite +running and having it broken. Ideally, you would run every test in your +suite every time you change a method. Practically, your suite will soon +grow too large to run all the time. Try to optimize your setup code so +you can run all the tests. Or, at the very least, create special suites +that contain all the tests that might possibly be affected by your current +development. Then, run the suite every time you compile. And make sure +you run every test at least once a day: overnight, during lunch, during +one of those long meetings…. +<h1> +<a NAME="Conclusion"></a>Conclusion</h1> +This article only scratches the surface of testing. However, it focuses +on a style of testing that with a remarkably small investment will make +you a faster, more productive, more predictable, and less stressed developer. +<p>Once you've been test infected, your attitude toward development is +likely to change. Here are some of the changes we have noticed: +<p>There is a huge difference between tests that are all running correctly +and tests that aren't. Part of being test infected is not being able to +go home if your tests aren't 100%. If you run your suite ten or a hundred +times an hour, though, you won't be able to create enough havoc to make +you late for supper. +<p>Sometimes you just won't feel like writing tests, especially at first. +Don't. However, pay attention to how much more trouble you get into, how +much more time you spend debugging, and how much more stress you feel when +you don't have tests. We have been amazed at how much more fun programming +is and how much more aggressive we are willing to be and how much less +stress we feel when we are supported by tests. The difference is dramatic +enough to keep us writing tests even when we don't feel like it. +<p>You will be able to refactor much more aggressively once you have the +tests. You won't understand at first just how much you can do, though. +Try to catch yourself saying, "Oh, I see, I should have designed this thus +and so. I can't change it now. I don't want to break anything." When you +say this, save a copy of your current code and give yourself a couple of +hours to clean up. (This part works best you can get a buddy to look over +your shoulder while you work.) Make your changes, all the while running +your tests. You will be surprised at how much ground you can cover in a +couple of hours if you aren't worrying every second about what you might +be breaking. +<p>For example, we switched from the Vector-based implementation of MoneyBag +to one based on HashTable. We were able to make the switch very quickly +and confidently because we had so many tests to rely on. If the tests all +worked, we were sure we hadn't changed the answers the system produced +at all. +<p>You will want to get the rest of your team writing tests. The best way +we have found to spread the test infection is through direct contact. The +next time someone asks you for help debugging, get them to talk about the +problem in terms of a fixture and expected results. Then say, "I'd like +to write down what you just told me in a form we can use." Have them watch +while you write one little test. Run it. Fix it. Write another. Pretty +soon they will be writing their own. +<p>So- give JUnit a try. If you make it better, please send us the changes +so we can spread them around. Our next article will double click on the +JUnit framework itself. We will show you how it is constructed, and talk +a little about our philosophy of framework development. +<p>We would like to thank Martin Fowler, as good a programmer as any analyst +can ever hope to be, for his helpful comments in spite of being subjected +to early versions of JUnit. +<h1> +References</h1> + +<ol> +<li> +<a NAME="Gamma, E., et al. Design Patterns: Elements of"></a>Gamma, E., +et al. Design Patterns: Elements of Reusable Object-Oriented Software, +Addison-Wesley, Reading, MA, 1995</li> + +<li> +<a NAME="Beck, K. Smalltalk Best Practice Patterns,"></a>Beck, K. Smalltalk +Best Practice Patterns, Prentice Hall, 1996</li> +</ol> + +<hr SIZE=1 WIDTH="100%"> +</body> +</html> |