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:[EMAIL PROTECTED] > 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: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] > > > --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
