You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cactus-user@jakarta.apache.org by la...@masq.ca on 2002/04/24 18:50:10 UTC

Refactoring question

Hi,

We're building a servlet which receives some parameters as input and calls a
handler based on the input parameters. How that works is that one of the
parameters is used as the JNDI name of the home interface of the handler. We
pass that parameter to a static utility method which will return the home
interface of that handler. So something like this:

String jndiName = httpRequest.getParameter("name");
HandlerHome home = EjbUtil.lookupHome(Handler.class, jndiName);
Handler handler = home.create();
Response response = handler.execute();
httpResponse.print(response.toString());
.
.
.

or something similar to this. All this nice stuff is going on in the
servlet's service() method. So evidently, it's untestable unless you have
the whole container running. In order to test properly, there needs to be a
refactoring of the service method so that I can write a test for it
specifically, without needing to have a container running that will give me
the correct home for the handler and all the rest of that. Has anyone done
anything similar? What type of refactoring did you do?

I think the main problem in this case is the Handler. The name of the
handler associated with each JNDI name is defined in the deployment
descriptor for the application. Is my option, then, to modify the deployment
descriptior on the fly (a bit like it's explained in the FAQ for web.xml)
and to create a stubbed handler just for testing purposes? Or is there a
more obvious way to do this that I can't see?

Thanks for all the help,

L (who will eventually contribute back)

-- 
Laurent Duperval <ma...@masq.ca>

Do you need a silencer if you are going to shoot a mime?



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Refactoring question

Posted by la...@masq.ca.
On 24 Apr, Nicholas Lesiecki wrote:
> I actually have an article coming out on IBM developerWorks in May on
> testing just such a situation. :) The short answer is to use AspectJ to
> replace certain calls (for instance, to your EjbUtil class) when running
> tests. The article runs a test suite in Cactus that I'm eventually going to
> work into one of the sample applications. If you're interested, you can
> start by checking out:
> 
> http://www.aspectj.org
> or
> http://www-106.ibm.com/developerworks/library/j-aspectj/index.html
> 

Ok, I'll look this over.

> I'm kind of amused by reading your code, it looks almost exactly like some
> code I've written, right down to:
> 
> HandlerHome home = EjbUtil.lookupHome(Handler.class, jndiName);
> 

What is it they say about great minds? :-)

L

-- 
Laurent Duperval <ma...@masq.ca>

HELLER'S LAW
    The first myth of management is that it exists.



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


RE: Refactoring question

Posted by Nicholas Lesiecki <ni...@eblox.com>.
I actually have an article coming out on IBM developerWorks in May on
testing just such a situation. :) The short answer is to use AspectJ to
replace certain calls (for instance, to your EjbUtil class) when running
tests. The article runs a test suite in Cactus that I'm eventually going to
work into one of the sample applications. If you're interested, you can
start by checking out:

http://www.aspectj.org
or
http://www-106.ibm.com/developerworks/library/j-aspectj/index.html

I'm kind of amused by reading your code, it looks almost exactly like some
code I've written, right down to:

HandlerHome home = EjbUtil.lookupHome(Handler.class, jndiName);

I think our static class is called EJBUtils, and the order of parameters is
reversed :)

Cheers,

Nicholas Lesiecki
Principal Software Engineer
eBlox, Inc.
(520) 615-9345 x104
Check out my new book!:
Java Tools for Extreme Programming: Mastering Open Source Tools, including
Ant, JUnit, and Cactus

http://www.amazon.com/exec/obidos/ASIN/047120708X/

Check out my article on AspectJ:
http://www-106.ibm.com/developerworks/library/j-aspectj/index.html


-----Original Message-----
From: laurent.duperval@masq.ca [mailto:laurent.duperval@masq.ca]
Sent: Wednesday, April 24, 2002 9:50 AM
To: Cactus Mailing List
Subject: Refactoring question

Hi,

We're building a servlet which receives some parameters as input and calls a
handler based on the input parameters. How that works is that one of the
parameters is used as the JNDI name of the home interface of the handler. We
pass that parameter to a static utility method which will return the home
interface of that handler. So something like this:

String jndiName = httpRequest.getParameter("name");
HandlerHome home = EjbUtil.lookupHome(Handler.class, jndiName);
Handler handler = home.create();
Response response = handler.execute();
httpResponse.print(response.toString());
.
.
.

or something similar to this. All this nice stuff is going on in the
servlet's service() method. So evidently, it's untestable unless you have
the whole container running. In order to test properly, there needs to be a
refactoring of the service method so that I can write a test for it
specifically, without needing to have a container running that will give me
the correct home for the handler and all the rest of that. Has anyone done
anything similar? What type of refactoring did you do?

I think the main problem in this case is the Handler. The name of the
handler associated with each JNDI name is defined in the deployment
descriptor for the application. Is my option, then, to modify the deployment
descriptior on the fly (a bit like it's explained in the FAQ for web.xml)
and to create a stubbed handler just for testing purposes? Or is there a
more obvious way to do this that I can't see?

Thanks for all the help,

L (who will eventually contribute back)

--
Laurent Duperval <ma...@masq.ca>

Do you need a silencer if you are going to shoot a mime?



--
To unsubscribe, e-mail:
<ma...@jakarta.apache.org>
For additional commands, e-mail:
<ma...@jakarta.apache.org>


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Refactoring question

Posted by la...@masq.ca.
On 24 Apr, Vincent Massol wrote:
>> In order to test properly, there needs to be
>> a
>> refactoring of the service method so that I can write a test for it
>> specifically, without needing to have a container running that will
> give
>> me
>> the correct home for the handler and all the rest of that. 
> 
> Do you mean you don't want to do Cactus testing but rather pure JUnit
> (outside of the container) ? If so, why ?
> 

No, not at all. You answered my question later.

>> Has anyone done
>> anything similar? What type of refactoring did you do?
>> 
> 
> yes, I have but I need to know more what's the intent.
> 

You answer that later also.

> Ok, you want to mock the Handler, right and only test the service()
> method, is that it ?

Exactly! Actually, I have to mock the handler because of the way service()
is written.

> If so, it is easy, simply mock
> (http://www.mockobjects.com) EjbUtil. You'll need to refactor your
> EjbUtil into a non-static class  like :
> 

<snip>

Hey thanks! Let me study this and AspectJ to see which way to go.

L

-- 
Laurent Duperval <ma...@masq.ca>

DENNISTON'S LAW
    Virtue is its own punishment.



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


RE: Refactoring question

Posted by Vincent Massol <vm...@octo.com>.

> -----Original Message-----
> From: laurent.duperval@masq.ca [mailto:laurent.duperval@masq.ca]
> Sent: 24 April 2002 17:50
> To: Cactus Mailing List
> Subject: Refactoring question
> 
> Hi,
> 
> We're building a servlet which receives some parameters as input and
calls
> a
> handler based on the input parameters. How that works is that one of
the
> parameters is used as the JNDI name of the home interface of the
handler.
> We
> pass that parameter to a static utility method which will return the
home
> interface of that handler. So something like this:
> 
> String jndiName = httpRequest.getParameter("name");
> HandlerHome home = EjbUtil.lookupHome(Handler.class, jndiName);
> Handler handler = home.create();
> Response response = handler.execute();
> httpResponse.print(response.toString());
> .
> .
> .
> 
> or something similar to this. All this nice stuff is going on in the
> servlet's service() method. So evidently, it's untestable unless you
have
> the whole container running. 

Or using mock objects, but in-container is better for you I'd say.

> In order to test properly, there needs to be
> a
> refactoring of the service method so that I can write a test for it
> specifically, without needing to have a container running that will
give
> me
> the correct home for the handler and all the rest of that. 

Do you mean you don't want to do Cactus testing but rather pure JUnit
(outside of the container) ? If so, why ?

> Has anyone done
> anything similar? What type of refactoring did you do?
> 

yes, I have but I need to know more what's the intent.

> I think the main problem in this case is the Handler. The name of the
> handler associated with each JNDI name is defined in the deployment
> descriptor for the application. Is my option, then, to modify the
> deployment
> descriptior on the fly (a bit like it's explained in the FAQ for
web.xml)
> and to create a stubbed handler just for testing purposes? Or is there
a
> more obvious way to do this that I can't see?
> 

stubs are no good, use mocks instead ;-)

Ok, you want to mock the Handler, right and only test the service()
method, is that it ? If so, it is easy, simply mock
(http://www.mockobjects.com) EjbUtil. You'll need to refactor your
EjbUtil into a non-static class  like :

public interface HandlerFactory
{
   public Object getHandler(String jndiName);
}

and a DefaultHandlerFactory implementation class.

Then in your servlet class, create a :

public (or protected) void setHandlerFactory(HandlerFactory);

Then in your Servlet init() method :

public void init()
{
    setHandlerFactory(new DefaultHandlerFactory);
}

Then in your test case :

public void testXXX()
{
    MyServlet servlet = new MyServlet();
    servlet.init(config);
    MockHandlerFactory mhf = new MockHandlerFactory();
    MockHandler mh = new MockHandler();
    [...]
    mhf.setHandler(mh);
    [...]
    servlet.setHandlerFactory(mhf);

    // test
    servlet.service(request, response);

    // asserts
}

For example. Of course MockHandlerFactory.getHandler() will return a
MockHandler mock.

An alternative :
----------------

in you servlet have a :

public Handler getHandler(String jndiName)
{
    HandlerHome home = EjbUtil.lookupHome(Handler.class, jndiName);
    Handler handler = home.create();  
    Return handler;
}

And then create a subclass of your servlet : 

public class TestServlet extends MyServlet
{
   public Handler getHandler(String jndiName)
   {
      return this.handler;
   }

   public void setHandler(Handler handler)
   {
      this.handler = handler;
   }
}   

And in your test class :

public void testXXX()
{
    MyServlet servlet = new TestServlet();
    servlet.init(config);
    MockHandler mh = new MockHandler();
    [...]
    servlet.setHandler(mh);

    // test
    servlet.service(request, response);

    // asserts  
}

-Vincent

> Thanks for all the help,
> 
> L (who will eventually contribute back)
> 
> --
> Laurent Duperval <ma...@masq.ca>
> 
> Do you need a silencer if you are going to shoot a mime?
> 
> 
> 
> --
> To unsubscribe, e-mail:   <mailto:cactus-user-
> unsubscribe@jakarta.apache.org>
> For additional commands, e-mail: <mailto:cactus-user-
> help@jakarta.apache.org>



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>