jakarta-cactus-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Mark Lybarger" <Mark.Lybar...@CBC-Companies.com>
Subject RE: how to test Session Facade without database
Date Fri, 23 Apr 2004 12:29:49 GMT
Thank you very much for the reply J.B.  I will definately take a lot of this into consideration
and will have to check for a copy of that Recipe companion you mention.  

> -----Original Message-----
> From: J. B. Rainsberger [mailto:jbrains@rogers.com]
> Sent: Thursday, April 22, 2004 11:29 AM
> To: Cactus Users List
> Subject: Re: how to test Session Facade without database
> 
> 
> Mark Lybarger wrote:
> 
> >>Get rid of the class-level (static) methods immediately, and 
> >>if you can, 
> >>quickly. They provide no value unless you consider 
> excessive coupling 
> >>valuable. :)
> > 
> > What would you suggest? This is getting a little off from 
> cactus (another forum suggestion?), but I'd really like to 
> test my ejbs since these components are now starting to 
> contain functionality that's reusable by other systems.  
> 
> We can take this over to TDD or JUnit, if you like. I don't 
> think Vince 
> minds, though -- do you, Vince? :)
> 
> > I notice in the "Junit In Action" book, the bean 
> implementation is being tested directly.  My issue is that my 
> beans are dependant on remote resources obtained during the 
> create method. 
> 
> Because your EJB performs JNDI lookups, you will want to refactor the 
> methods that use those resources. The general approach -- which I 
> outline in JUnit in Action's "companion" volume JUnit Recipes 
> :) -- is 
> to extract the code that uses the JNDI-bound object into a separate 
> method taking the JNDI-bound object as a parameter. Then you can test 
> this second method without involving JNDI at all. Perhaps I can 
> "refactor" your code to demonstrate. (I'll try.)
> 
> 
> Say I have the following:
> > 
> > OrderBean {
> >    ejbCreate () {  // get remote reference to cust bean, 
> get ds name from IC }
> >    postOrder ( Order order ) throws CustomerNotFoundException { 
> > 	customer.verifyCustomer ( order.getCustomerId() );
> >       OrderPeer.insertOrder( order );
> >    }
> > }
> 
> So here, 'customer' is a field of OrderBean? If so..
> 
> doPostOrder(Customer customer, Order order) throws 
> CustomerNotFoundException {
>      customer.verifyCustomer(order.getCustomerId());
>      OrderPeer.insertOrder(order);
> }
> 
> postOrder(Order order) throws ... {
>      doPostOrder(customer, order);   // Using the field
> }
> 
> Now, since Customer and Order are both interfaces, it should 
> be trivial 
> to fake them both either with POJO implementations or 
> EasyMock/jMock. To 
> test doPostOrder(), simply invoke it look a POJO.
> 
> Now the only /bad/ news is that OrderPeer is still there, which is a 
> pain. Is this Torque-generated code, by chance? You may wish 
> to wrap all 
> that in an interface such as OrderRepository, with an implementation 
> that delegates to your Peer objects. Now....

they're not torque generated.  when the system was first put together, the team couldn't get
torque working with our weblogic/oracle datasource, so there is a custom written persistance
layer that _kinda_ sounds like torque. 

> 
> OrderBean {
>      ejbCreate() {
>          // JNDI lookups for fields customer, dataSource and 
> orderRepository!
>      }
> 
>      doPostOrder(Customer customer, Order order, OrderRepository 
> orderRepsitory) ... {
>          customer.verifyCustomer(order.getCustomerId());
>          orderRepository.insertOrder(order);
>      }
> 
>      postOrder(Order order) throws .... {
>          doPostOrder(customer, order, orderRepository);   // fields
>      }
> }
> 
> Now you can test doPostOrder() /entirely/ in memory and without the 
> container. Simply bind the OrderRepositoryPeerImpl somewhere in your 
> JNDI directory, or use some other Singleton to store it.
> 
> > CustomerBean {
> >    ejbCreate () { //get ds name from IC }
> >    verifyCustomer( custId ){ 
> >      // get db connection from ds.
> >      Connection conn = DbConnectionTool.getConnection ( 
> datasourceName );
> >      CustomerPeer.verifyCustomer( custId, conn );
> >    }
> > }
> 
> The same technique will work here, but now the connection is 
> annoying. 
> Since the CustomerPeer is stateless, we can easily make it a 
> short-lived 
> object and create it when needed.
> 
> CustomerBean {
>      verifyCustomer(Long customerId) {
>          customerRepository.verify(customerId, new 
> CustomerRepositoryJdbcImpl(DbConnectionTool.getConnection(data
> SourceName)));
>      }
> 
>      doVerifyCustomer(Long customerId, CustomerRepository 
> customerRepository) ... {
>          customerRepository.verifyCustomer(customerId);
>      }
> }
> 
> Again, it's easy to test doVerifyCustomer without the container or a 
> database!
> 
> 
> > CustomerPeer {
> >    public static verifyCustomer ( custId, conn) throws 
> CustomerNotFoundException {
> >      PreparedStatement prepStmt = 
> conn.prepareStatement("select customerId from customer where 
> cust id = ?");
> >      prepStmt.setInt(1,custId);
> >      prepStmt.execute();
> >      resultSet = prepStmt.executeQuery();
> >      // here is code that says "if cust not found, throw 
> custnotfound exception.
> >    }
> > }
> 
> This is now...
> 
> /**
>   * Don't use me for long. I hold on to connections, and so I should
>   * be sent out for garbage collection as soon as possible.
>   */
> CustomerRepositoryJdbcImpl implements CustomerRepository {
>      private Connection connection;
> 
>      public CustomerRepositoryJdbcImpl(Connection connection) {
>          this.connection = connection;
>      }
> 
>      public void verifyCustomer(Long customerId) throws ... {
>          // code from above
>      }
> }
> 
> This is exactly how I did things on a recent project and it 
> has worked 
> very well. I'm not entirely comfortable with the Singleton 
> DbConnectionTool, but I understand why it has to be that way. 
> You could 
> turn the CustomerRepositoryJdbcImpl into a Singleton as well, 
> if you're 
> uncomfortable with all that extra object creation/destruction.
> 
> > I'm comfortable with mocking up classes that aren't being 
> tested, but I don't really like the idea of doing things to 
> my code that forces me to create a Testable version of my EJB 
> that extends the actual EJB.
> 
> Don't extend the EJB: instead, extract from the EJB all the 
> logic, then 
> test the logic separately.

this is the challenging part.  what is, and what isn't the logic.  _what_ is being tested.
 
> 
> An EJB should be nothing more than a simple wrapper around real 
> application or domain logic, providing EJB-related services. An EJB 
> should do nothing interesting on its own.
> 
> > sometimes its just nice to let the qa guys handle testing ;).
> 
> It is /never/ nice to let the QA guys handle Programmer Testing. 
> /Never/. Never, never, never, never, never. Never.

i agree.  it's just that sometimes i'm struggling to see much value of testing _after_ all
this code is written.  
> -- 
> J. B. Rainsberger,
> Diaspar Software Services
> http://www.diasparsoftware.com :: +1 416 791-8603
> Let's write software that people understand
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: cactus-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: cactus-user-help@jakarta.apache.org
> 
> 
> 


Mime
View raw message