◆ Problem
You want to verify your container-managed transactions.
◆ Background
Transaction-based programming can be complex, which is one of the reasons for the J2EE container-managed transaction feature. The goal of this feature is to allow you to specify transactions without having to code all the dirty details. The simplic- ity of container-managed transactions often leaves programmers feeling as though it were “too easy,” and they sometimes worry that the application will not behave as expected under a large, concurrent load. Because they know that transaction- based programming is complex, they feel as though they should have to “do more”
to add transactional behavior to an application. Testing container-managed trans- actions is not complex at all, once you put some trust in the container. This recipe helps you focus on testing your work, and not the work of the container.
◆ Recipe
The most direct approach you can take involves verifying the container-managed transaction attributes set in your deployment descriptors. When you do this, you are not testing whether your transaction settings make sense for the application, but rather that the transaction settings are what you think they should be. This kind of test largely protects against someone unknowingly (or carelessly) chang- ing the settings. This kind of test alerts you to any changes so that you can make a sound judgment whether the change is appropriate. It merely avoids the unpleas- ant task of debugging a test or production problem and tracing it all the way back to a transaction isolation level that could not possibly work. Avoid the problem by verifying your deployment descriptors. You can do this using the techniques in chapter 9, “Testing and XML.”
You may develop additional Deployment Tests to enforce your own deploy- ment rules. As an example, you might decide that all entity bean component methods (on the remote and local interfaces) must be deployed with the transac- tion attribute Required.15 In this case, you could certainly write a test to verify those settings, such as the one that follows. The test in listing 13.12 verifies that
15This is not a suggestion; rather just an example.
537 Test container-managed transactions
the transaction attribute for any container transaction involving the component methods of a particular EJB is Required. Note how complex it is. 16
package junit.cookbook.coffee.model.ejb.test;
import java.io.*;
import org.apache.xpath.XPathAPI;
import org.custommonkey.xmlunit.*;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
public class EntityBeanTransactionAttributeTest extends XMLTestCase { protected void setUp() throws Exception {
XMLUnit.setIgnoreWhitespace(true);
}
public void testOrder() throws Exception { doTestTransactionAttribute(
"../CoffeeShopLegacyEJB/META-INF/ejb-jar.xml", "Order");
}
private void doTestTransactionAttribute(
String ejbDeploymentDescriptorFilename, String ejbName)
throws Exception {
Document ejbDeploymentDescriptor = XMLUnit.buildTestDocument(
new InputSource(
new FileInputStream(
new File(ejbDeploymentDescriptorFilename))));
String transactionAttributeXpath =
"/ejb-jar/assembly-descriptor/container-transaction"
+ "[method/ejb-name='" + ejbName + "' and "
+ "(method/method-intf='Remote' or "
+ "method/method-intf='Local')]"
+ "/trans-attribute";
NodeList transactionAttributeNodes = XPathAPI.selectNodeList(
ejbDeploymentDescriptor, transactionAttributeXpath);
Listing 13.12 EntityBeanTransactionAttributeTest
16The tests here will fail without an internet connection, because XMLUnit will try to validate the XML document against its DTD. For further details, see recipe 9.2, “Ignore the order of elements in an XML document,” and read the section entitled, “Network connectivity and the DTD.”
538 CHAPTER 13
Testing J2EE applications
assertTrue(
"No transaction attribute setting for " + ejbName + " EJB", transactionAttributeNodes.getLength() > 0);
for (int i = 0;
i < transactionAttributeNodes.getLength();
i++) {
Node each = transactionAttributeNodes.item(i);
Text text = (Text) each.getFirstChild();
Node assemblyDescriptorNode =
each.getParentNode().getParentNode();
assertEquals(
"Transaction attribute incorrect at "
+ assemblyDescriptorNode.toString(), "Required",
text.getData());
} } }
We have already factored out a generic version of the test so that you can convert this into a Parameterized Test Case (see recipe 4.8, “Build a data-driven test suite”), looping over all the entity beans in your system. Due to the inherent flexi- bility in describing container-managed transactions, we need a particularly long and convoluted XPath expression to match them all: any container-transaction node that contains the ejb-name we are looking for and either the Remote or Local method-intf. It would take even seasoned XPath users a moment or two to realize what this test is doing, so naming it is particularly important. As we wrote previously, you could write this kind of test, but we find it to be too complex.
Instead, we recommend generating your EJB deployment descriptors from a pro- cess that can more easily enforce this deployment rule. If you use XDoclet (http:/
/xdoclet.sourceforge.net/) to generate your EJB deployment descriptors, then you could use XJavaDoc—the standalone JavaDoc engine—to parse your entity bean implementation class source files and make assertions as to the value of each entity bean’s @ejb.transaction type property. We recommend that you try a few different approaches and see what works best for you.
◆ Discussion
In this recipe we made it clear what we were testing: that the transaction attribute set in your deployment descriptors is what you think it should be. There is the other question: how do you test that such a transaction attribute produces the
539 Test container-managed transactions
desired results? Typically one chooses transaction attributes and transaction isola- tion levels based on reasoning about the system and live experiments. We will not discuss how to discern which transaction settings are appropriate, as that is the not the goal of this book.17 As for live experiments, there are several commercial—and perhaps some viable noncommercial—tools that one can use to simulate heavy load for web applications. There are performance testing packages built on JUnit, such as JUnitPerf (www.clarkware.com/software/JUnitPerf.html); and the combi- nation of JUnitPerf and HtmlUnit can help you implement load tests driving a web application. Whatever tools you choose, there is no substitute for deploying your application on a production quality machine, letting 1000 simulated users loose on it and monitoring the error log. Or, as Ron Jeffries said, “Speculation or experi- mentation—which is more likely to give the correct answer?”
◆ Related
■ 4.8—Build a data-driven test suite
■ Chapter 9—Testing and XML
■ JUnitPerf (www.clarkware.com/software/JUnitPerf.html)
■ XDoclet (http://xdoclet.sourceforge.net/)
17See Greg Barish, Building Scalable and High-Performance Java Web Applications Using J2EE Technology (Addison-Wesley, 2001). The title is a mouthful, but the content is well worth it.
TE AM FL Y
Team-Fly®