| By Ted Husted | Article Rating: |
|
| December 24, 2007 11:00 PM EST | Reads: |
19,188 |
If we run the characterization tests against the original classes, the classes will pass with flying colors (well, green), as shown in Figure 3. This is to be expected: characterization tests will always work against the unmodified code under test, because the tests are based on what the code actually does-good, bad, or indifferent.
Since the JPetStore Domain is designed with JavaBeans, many of these tests are simple exercises of getters and setters. Other more interesting tests peer into the business logic as Listing 5 shows.
JUnit Factory realized that if it sets the ListPrice on a single CartItem and then calls getTotalPrice(), it will get a value equal to ListPrice. In other words, if there's only one item in the shopping cart, the total price for everything in the cart is the same as the price of that one item.
Very Interesting - But a Bug!
Listing 6 shows another "interesting" characterization test.
The test is telling us that if the line items are set to null, the system will throw a runtime NullPointerException. Remember, a characterization test documents what the code under test actually does: JUnit Factory isn't offering an opinion of the correctness of that behavior.
Let's look at Listing 7, which shows bits of the code under test.
Class Order instantiates lineItems then initializes it to an empty ArrayList(). As written, other parts of the class simply assume that lineItems will never be null. But since there is a public setLineItems method, the non-null assumption seems rash. Being prudent programmers, we decide to fix this latent bug before it crawls out of the woodwork: the fix is to apply "lazy instantiation" to the lineItems field, as Listing 8 shows.
To finish the job, we make sure that the class is calling its own getter method throughout rather than accessing the field directly. (A good practice under any circumstances!)
If we clear the tests (by deleting the agitar/test folder) and regenerate, JUnit Factory will return us one fewer test.
Looking back, we see that JUnit Factory uncovered the missing null-guard just by analyzing the code. It also discovered the relationship between list price of an item and the total price of an order, all without being told. Hmmm...I wonder what it could do if we could give JUnit Factory a clue as to how the domain objects are supposed to work?
Generate Better Tests with Realistic Test Data
In
the context of the JPetStore application, Items are magical objects
that appear fully formed from the database (via Data Access Objects).
JPetStore is a consumer-facing shopping cart application: the
application never creates an Item itself. All it does is wrap Items in
CartItems, which go into the shopping Cart.
We could generate more useful tests by providing a realistic set of Item objects rather than let JUnit Factory create them willy-nilly. To create realistic objects, we can write a Test Data Helper.
Essentially, by implementing the TestHelper "marker" interface, we create a simple factory that provides well-formed objects. When JUnit Factory needs an instance of a particular class, it looks to see if there are any helper methods available that return objects of that class. If any of these helper objects will work for the test JUnit Factory is trying to generate, it will give the helper objects priority over test objects it creates from scratch.
Using our inside knowledge of what kind of items appear in our database, we can write a TestHelpers class that provides realistic Item objects for our tests to use, as Listing 9 shows.
With TestHelpers in place, the generated tests will reference our factory methods, instead of creating objects from whole cloth. Listing 10 is an example.
Instead of making something up, the testToString method calls the toString method on one of our TestHelper classes. The toString form is a concatenation of the item ID and the product ID. Just by glancing at the generated test, we can see that it is characterizing the code correctly - thanks in part to our TestHelpers class that provided realistic data for the tests.
Extend the Business Logic with Confidence
Now that we have a set of characterization tests, we can get to work on the business end of the application.
•
We can study each test suite alongside the code under test to help us
better understand how the legacy application actually works.
• Along the way, if we note "suspicious" or "unexpected" behavior
in a test, we can dig deeper to see if there's a latent bug that may
complicate maintenance.
• We can extend and refactor the application with confidence, since
our characterization tests will alert us of unintended consequences.
• When we do decide to change the behavior of the application, we
can regenerate the characterization tests as a new baseline for future
changes.
Characterization tests are unit tests, but they should not be all the unit tests. We should still write a smaller set of custom tests, particularly as we create new classes and methods. But, with JUnit Factory in our tool belt, we can focus our time on custom tests that exercise key features, while the tool generates the bulk of the boring, but valuable, characterization tests.
Published December 24, 2007 Reads 19,188
Copyright © 2007 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Ted Husted
Ted Husted (http://husted.com/ted/) is a software engineer and an active member of several open source projects hosted by the Apache Software Foundation, including Struts and iBATIS. His books include JUnit in Action, Struts in Action, and Professional JSP Site Design. Ted is also a consultant for Agitar Software, Inc.
![]() |
Alexander Klimuk 01/14/08 06:37:02 PM EST | |||
This article resembles the video of Alberto Savoia from Agitar, which is available as of Sep 2007 at 'theserverside.com': Well, a bit different wording, and that's all. Why haven't you just placed a link to that video and discussion on TSS site? Regards, |
||||
- Kindle 2 vs Nook
- Why IBM’s Server Chief Got Busted
- Industry Experts Discuss the State of Cloud Computing
- Cloud Computing Expo: Exclusive Q&A with Yahoo! SVP Cloud Computing
- Performance Tuning Essentials for Java
- Confessions of a Ulitzer Addict
- It's the Java vs. C++ Shootout Revisited!
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- Ulitzer Aid Campaign for the Typhoon Ondoy Victims
- Cloud Computing Can Revitalize Your Career as Software Developer
- A Brief History of Cloud Computing
- Oracle & Cloud Computing: Exclusive Q&A with SVP Richard Sarwal
- Kindle 2 vs Nook
- Cloud CEOs, CTOs & SVPs to Speak at 4th International Cloud Computing Expo
- Why IBM’s Server Chief Got Busted
- Industry Experts Discuss the State of Cloud Computing
- The Difference Between Web Hosting and Cloud Computing
- Cloud Computing Expo: Exclusive Q&A with Yahoo! SVP Cloud Computing
- Performance Tuning Essentials for Java
- Ajax in RichFaces 3.3, JSF 2 and RichFaces 4
- Confessions of a Ulitzer Addict
- It's the Java vs. C++ Shootout Revisited!
- The End of IT 1.0 As We Know It Has Begun
- My Thoughts on Ulitzer
- A Cup of AJAX? Nay, Just Regular Java Please
- Java Developer's Journal Exclusive: 2006 "JDJ Editors' Choice" Awards
- The i-Technology Right Stuff
- JavaServer Faces (JSF) vs Struts
- Rich Internet Applications with Adobe Flex 2 and Java
- Java vs C++ "Shootout" Revisited
- Bean-Managed Persistence Using a Proxy List
- Reporting Made Easy with JasperReports and Hibernate
- Creating a Pet Store Application with JavaServer Faces, Spring, and Hibernate
- What's New in Eclipse?
- Why Do 'Cool Kids' Choose Ruby or PHP to Build Websites Instead of Java?
- i-Technology Predictions for 2007: Where's It All Headed?


































