JaVa
   

Enterprise JavaBeans

EJBs are Java components running in an EJB container. This container is responsible for the lifespan of the components and for transactional behavior, persistence, load distribution, and security. A good introduction to coding with EJBs has been done by Monson-Haefel [Monson01]. Test-first development in micro-iterations works best when the unit tests are running in an isolated and fast way. But how are we supposed to run the test suite every 10 minutes or so, when the deployment of an EJB component can take several minutes? And how can we isolate a component's test when the behavior of this component depends on specific configurations in the deployment descriptor? The problems occurring in EJB testing are similar to those in testing persistent objects (see ), only worse by one order of magnitude. What we find here is strong state dependent behavior and inextricable dependencies on the configuration of the app server used. In addition, the deployment of the components takes too much time. Considering all of the above, it doesn't come as a surprise that the attempt to replace an EJB container, or its interfaces, respectively, by dummy or mock objects for unit testing is doomed to fail. [4] The behavior of a container influences so many aspects that the effort involved in developing suitable dummies comes very close to developing a real container. In addition, the deployment descriptor of an EJB has a major impact on that EJB's behavior. For these reasons, we also have to simulate the deployment.

The above scenario suggests that EJBs should best be tested in the context of an EJB container (i.e., an app server). This means that all who hoped to find a simple solution for fast and isolated EJB unit testing in this chapter will be disappointed.

Just a Facade

Fortunately, the situation is not hopeless. We can at least reduce the number of necessary container tests to a minimum. To this end, instead of implementing the actual app logic directly in EJBs, we use a lower layer. The beans serve only as a facade of the actual business logic. Although it is not always possible, we can design our enterprise beans so that they directly map the business objects. This gives us a way to generate EJBs from these business objects. In this case, we have to test only the generator, but not the beans themselves. Whether or not coding a generator represents the simplest solution depends on the number of EJBs we have to create. Peeters [01] includes a more detailed discussion of this approach. The Box Metaphor describes a set of rules on how EJBs as plain technology representatives can be separated from the core of an app. More specifically, each box consists of a vertical cross section of the actual business logic. To the outside, the box represents itself only by the interface of a facade. This interface (i.e., the EJB container in our case) has to be fully independent of the specific technology. The EJBs themselves represent the implementation of this facade. They are very simple, because they normally do nothing but delegate. If there are dependencies to entity beans, then these entity beans can usually be replaced by dummy implementations with little effort, because they are bare placeholders for data. [5]

One expansion to this approach consists in implementing bipolar Enterprise JavaBeans [Peeters01]. A bipolar EJB is an EJB that can be instantiated as a local object. "Clients" of the facade do not have to know whether an instance lives locally or in the container. This is achieved by defining the EJB's remote interface as an extension to the facade interface. At runtime, a factory object selects the EJB form, which can be either local or remote. In this case, too, a generator can significantly reduce the effort involved in programming the two EJB forms. A similar direction is also taken by the local interfaces defined in the EJB 2.0 specification [URL:EJB]. [6]

Testing Inside the Container

Nygard and Karsjens [Nygard00] describe how EJBs can be tested inside the container. They recommend creating the InitialContext object and the home instances used in the setUp() method. The beans are then no longer instantiated in the test itself, but rather in their own factory methods. Schematically, an EJB test class could then look like this:

public class MyEjbTest extends Testcase {
 private MyEjbHome home;
 protected void setUp() throws Exception {
 Context initial = new Initialcontext();
 Object homeRef = initial.lookup("MyEjb");
 home = (MyEjbHome) PortableRemoteObject.narrow(
 homeRef, MyEjbHome.class);
 }
 private MyEjb createMyEjb(String par) throws RemoteException{
 return home.create(par);
 }
 public void testXXXX() throws Exception {
 MyEjb ejb = this.createMyEjb("test");
 // testing code
 }
}


There are times when test cases need the environment of the app server. In these cases, we cannot test from a remote client; we have to test within the server. Nygard [00] introduces a test runner servlet specifically for this purpose. This servlet runs on the app server and can trigger arbitrary test suites in the server. [7] An alternative is the use of Cactus [URL:Cactus], which also allows you to run unit tests from an app server. We will learn more about Cactus in the context of Web apps in , Web apps.

In view of the fact that the problems we've discussed can turn the execution of EJB tests into a time-consuming venture, it might be a good idea to run these tests mainly during the build phase of your project. In addition, it would then also be desirable to deploy the EJBs not only on one single app server, but to test for the EJBs' interaction with all targeted app servers at the same time. This task is a good target for combining JUnit and Ant—a make tool written in Java [URL:Ant].

EJBs and Simple Design

EJBs are "hip." It is not unusual in current software projects that a customer's only specific idea of the software under development is to absolutely use EJBs. If this strategic reason is not given, then it is worth thinking twice about the necessity of a heavy technology like Enterprise JavaBeans. From the perspective of an evolutionary development and design strategy, committing to EJBs at the beginning of a project is seldom justified. Vera Peeters [01] writes this:

Using EJB is definitely not the simplest thing to do. So how do EJBs fit with . . . the "Do The Simplest Thing That Could Possibly Work" principle? Well, to be honest, I think they don't. If you start developing a new system, chances aren't very high that you have a good reason to start using EJBs.

After a few iteration cycles, it may well be possible that some of the complex properties inherent in EJBs are really a good thing to have. [8] Before we are sure that this is so, however, we should spare ourselves the stress of deployment, additional complexity, and unavoidable test complications. Design principles like the Box Metaphor just introduced make it easier for us to take a specific technology to an independent level. I recommend this approach also for the introduction of all other technologies and frameworks that don't make us confident about their benefits from the very beginning of a project.

Another reason one might be inclined to include EJBs in a test-first development project arises when using existing code. But here, too, extracting the technology from the domain code into a layer of its own may allow us to migrate from EJB to simpler means later. [4]Unsuccessful attempts are frequently reported at [URL:YahooJUnit]. [5]Provided you stick to SUN's J2EE app patterns. [6]At the time of this tutorial's writing, the final release of the EJB 2.0 specification has been available for only a couple of months; 2.0-compliant app servers have reached the market only recently. [7]This also corresponds to the approach chosen by JUnitEE [URL:JUnitEE]. [8]Look at the work of Maier [01] to see how EJB features are weighed against actual project requirements.


JaVa
   
Comments