| By John Evans, Richard Cariens | Article Rating: |
|
| July 31, 2006 05:15 AM EDT | Reads: |
28,484 |
Testing Java code is increasingly a task taken on by developers rather than separate teams to which the programs are handed. Many Java developers are now familiar with JUnit and know the different between unit tests and integration tests. This has been driven largely by the focus on test-driven development (TDD) in extreme programming (XP) and other agile software development methodologies. While the industry-at-large has recognized the value of unit tests and has a new outlook on testing in general, for the most part, actual TDD (meaning, the tests are written first) is not usually practiced outside of hardcore agile shops.
In this article, we'll present a specific example (based on a real-world scenario that we recently faced) and walk step-by-step how to take a pure TDD approach and hopefully show the benefits of embracing TDD completely in this scenario. (For a clear and concise explanation of some of the major benefits of TDD in general, see www.extremeprogramming.org/rules/testfirst.html.)
The Scenario
This scenario is modeled closely on one we faced at a client site recently. In short, we were a pair on a development team working on a project with typical issues:
- A deadline/delivery date had been set
- Little or no requirements existed and
- It didn't look like we'd be getting requirements any time soon (due to limited staffing, etc.).
- A "feed finder" service: the user must be able to enter a URL somewhere on the site that will produce a list of candidate feed URLs that it found at that URL.
- A "feed validation" service: the site will analyze a user-provided URL and inform the user if the document found at that URL is a valid RSS or Atom feed.
Constraints
The client's standard production platform is Java 5, JBoss 4.x, and MySQL 4.1 on Red Hat Linux. We're supplied with a workstation running Windows XP Pro, Eclipse 3.1, Java 5, and JBoss 4.0.1.
Decisions
We decided to assess the risk level of each service. RSS and Atom standards are well known and there are a variety of tools that we can probably use to implement the "feed validation" service, which doesn't feel that risky. The "feed finder" service feels much riskier since there are many ways to detect a candidate feed for a supplied URL, some of which are:
- We can try to discover the feed from the HTML document at the supplied URL using <link> elements in the HTML <head> section;
- We can spider the URL's Web site for common feed file names like rss.xml, atom.xml, rdf.xml, feed.rss, etc.;
- We can try to get the feed URL by using a Web Service like Syndic8's XML-RPC services.
Getting Started
We think it will be easier to write the tests if we break up the service into two discrete steps:
- Download the HTML document from the supplied URL;
- Parse/search the document for <link> tags with "type" attributes of "application/rss+xml," "application/atom+xml," "application/x.atom+xml," or "application/x-atom+xml."
For starters, we add a test for detecting RSS links that automatically fails (since we don't have anything to test yet) and we're ready to start defining success and failure criteria.
Note that even though we haven't written any application code, we know that we're probably headed towards creating a class called FeedAutoDiscoverer and that we're expecting this class to be able to find an RSS link in a document.
Writing the Test
Now we have to generate some input HTML that contains a <link> tag with a type of "application/rss+xml" (the Atom test will come later). We add a simple in-line HTML document that contains the expected link to our "testFindsRssLink" method.
Now we're ready to introduce the component that will implement the discovery logic. We replace the "fail" statement with a call to an instance of a class called FeedAutoDiscoverer. We decide that this class should implement a method called "discoverLinks" that accepts a string and returns a list of strings. We also add assertions that help us know if the FeedAutoDiscoverer discovered the RSS link type correctly:
- We know that our test input only has one <link> tag in it so we assert that the FeedAutoDiscoverer returns a list with one element;
- We know that our test input contains a <link> tag with a specific "href" attribute and we want to see that expected href value in the list (see Figure 2).
We tell Eclipse we want this class to live under the "src" source folder instead of the "tests" folder and then let the wizard generate the class for us.
Once the empty FeedAutoDiscoverer is generated, we still find we can't compile our test because the method "discoverLinks" method doesn't exist. We let Eclipse generate this for us as well (see Figure 3).
Eclipse generates an empty method for us with a handy "TODO" reminder that we'll eventually have to change this method.
The test will now compile and is ready for its first run. Of course it will fail, but that's to be expected since our FeedAutoDiscoverer just returns null.
Now that we've written the test, we can focus on making the test pass.
Making the Test Pass
We're going to try to write the simplest code that will make the test pass. We know there are several ways to detect a <link> tag in an HTML document:
- We can sub-class the HTMLEditorKit.ParserCallback from the javax.swing.text.html package;
- We could use a third-party HTML/XML parsing library like TagSoup, HotSax, NekoHTML, JTidy, etc;
- We could use regular expressions and other "brute force" techniques.
Published July 31, 2006 Reads 28,484
Copyright © 2006 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By John Evans
John Evans is the founder and president of JPEvans, Inc. (www.jpevans.com), a small independent computer consulting company based in Northern Virginia just outside of Washington D.C. John has over 10 years of professional experience in software development. He has successfully developed and deployed large-scale software systems for several large multi-national corporations.
More Stories By Richard Cariens
Richard Cariens is an independent software consultant in the Washington D.C. area (www.jpevans.com). He has over 10 years of experience testing, developing, designing, and architecting Internet technology and financial systems. Rich holds an MS in computer science from George Mason University in Fairfax, Virginia.
![]() |
The Cherbin 08/22/06 06:35:33 PM EDT | |||
The best way to write right java is either |
||||
![]() |
JDJ News Desk 07/30/06 11:36:06 AM EDT | |||
Testing Java code is increasingly a task taken on by developers rather than separate teams to which the programs are handed. Many Java developers are now familiar with JUnit and know the different between unit tests and integration tests. This has been driven largely by the focus on test-driven development (TDD) in extreme programming (XP) and other agile software development methodologies. While the industry-at-large has recognized the value of unit tests and has a new outlook on testing in general, for the most part, actual TDD (meaning, the tests are written first) is not usually practiced outside of hardcore agile shops. |
||||
![]() |
JDJ News Desk 07/30/06 08:56:13 AM EDT | |||
Testing Java code is increasingly a task taken on by developers rather than separate teams to which the programs are handed. Many Java developers are now familiar with JUnit and know the different between unit tests and integration tests. This has been driven largely by the focus on test-driven development (TDD) in extreme programming (XP) and other agile software development methodologies. While the industry-at-large has recognized the value of unit tests and has a new outlook on testing in general, for the most part, actual TDD (meaning, the tests are written first) is not usually practiced outside of hardcore agile shops. |
||||
![]() |
Jon Log 07/26/06 05:22:53 AM EDT | |||
Though the development in question is a trivial one, your conclusions encapsulate perfectly why TDD is a poor substitute for a proper development model: Conclusion 1: "It forced us to translate our ambiguous requirements into verifiable test criteria" But on whose terms ? The "us" in your statement implies that you mean the developer. This is WRONG. An ambiguity must be flattened out by the specifier and agreed on by the developer. This is the contract you have with whoever you are providing a solution for. A developer is just as likely to interpret an ambiguity incorrectly as correctly. Conclusion 2: "The test criteria helped us focus on doing just what was needed to pass the test, and thus hopefully satisfying the requirements" Well, "hopefully" is not good enough. The objective of the developer MUST be to make their code do what it should in relation to the requirement. By encouraging a coder to produce something that meets only the requirements of a test that they themselves have defined is obviously a corrupt concept. Focussing on the test rather than the true objective of the requirement breaks a valuable chain of responsibility that should exist at every stage of the process. Conclusion 3: "We avoided the heavy front-loading of design documentation and focused on getting some working code." This is the icing on the cake. Spending time thinking about and documenting a design delivers too many obvious benefits to mention. However, in relation to the anti-patterns that I believe are a core part of your conclusions, designing a solution before implementing it would force any ambiguities to be resolved at the correct time and in the correct manner (against a coherent definition that is intelligible to the business and development communities). In addition, assuming that a solution involves more that one method (which of course it generally does) it would promote the production of a more appropriate test path with the requirements taking precedence over the tests themselves. |
||||

























