You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cactus-dev@jakarta.apache.org by Christopher Lenz <cm...@gmx.de> on 2002/11/27 16:43:29 UTC

JspTagLifecycle: Testing JSP tag libraries with Cactus

Hi all,

[I'm cc-ing to taglibs-dev because I assume this is of interest there too.]

As some of you might have noticed, I've recently submitted a new 
extension class to Cactus that is supposed to help with the testing of 
JSP tag libraries.

In essence, the purpose is to free the developer from knowing all the 
ins and outs of the JSP tag extension API, and especially how the 
container and JSP compiler handles the tags. So instead of calling all 
the lifecycle methods (setPageContext, setParent, doStartTag, 
doAfterBody, etc, etc) directly - which is quite error-prone -, you 
delegate that to the JspTagLifecycle class. That class still gives you 
the power to verify just about every aspect of the tag under test, by 
providing points where the lifecycle can be intercepted by the test.

Here are a couple of examples copied directly from the Cactus 
Sample-Servlet test suite, which uses JspTagLifecycle to test the 
JSTL-core tags:

Example 1 (with body content)
-----------------------------

   /**
    * Tests the <code>&lt;c:out&gt;</code>-tag with a proper, literal
    * value for it's <code>value</code> attribute that contains special
    * XML characters that need to be escaped.
    */
   public void testOutTagEscapeXml()
     throws JspException, IOException {
     OutTag tag = new OutTag();
     tag.setEscapeXml("true");
     JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
     tag.setValue("<value/>");
     lifecycle.invoke();
   }
   public void endOutTagEscapeXml(WebResponse theResponse) {
     String output = theResponse.getText();
     assertEquals("&lt;value/&gt;", output);
   }

Example 2 (conditional)
-----------------------

   /**
    * Tests the conditional tag &lt;c:if&gt; by providing a proper,
    * literal value to it's <code>test</code> attribute that evaluates
    * to the boolean value <code>true</code>. The test verifies the
    * correct behaviour by asserting that the tag's body is not
    * skipped.
    */
   public void testIfTagTrue()
     throws JspException, IOException {
     IfTag tag = new IfTag();
     JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
     tag.setTest("true");
     lifecycle.invoke(new JspTagLifecycle.Interceptor() {
       public void skipBody() {
         fail("Body should have been evaluated!");
       }
     });
   }

Example 3 (iteration)
---------------------

   /**
    * Tests the tag &lt;c:forEach&gt; by providing a comma-delimited list
    * of string to it's <code>items</code> attributes, and checking the
    * exposed scoped variable on every iteration step.
    */
   public void testForEachTag()
     throws JspException, IOException {
     ForEachTag tag = new ForEachTag();
     JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
     tag.setVar("Item");
     tag.setItems("One,Two");
     lifecycle.invoke(new JspTagLifecycle.Interceptor() {
       public void evalBody(int iteration, BodyContent body) {
         String item = (String)pageContext.findAttribute("Item");
         assertNotNull(item);
         if (iteration == 0) {
           assertEquals("One", item);
         } else if (iteration == 1) {
           assertEquals("Two", item);
         } else if (iteration == 2) {
           assertEquals("Three", item);
         } else {
           fail("More iterations than expected!");
         }
       }
     });
   }

Now, while this API let's you test just about every aspect of the 
tag-under-test, I'm not quite sure whether it's really friendly, 
especially when it comes to nested/collaborative tags. I'm playing with 
a couple of ideas, and I'd very much appreciate feedback if you have any 
good ideas or general concerns.

First, I've been thinking about adding shortcut methods to verify that 
the body has been evaluated or skipped, so that [Example 2] could be 
written as follows:

     IfTag tag = new IfTag();
     JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
     tag.setTest("true");
     lifecycle.invoke();
     lifecycle.assertBodyEvaluated();

Similar shortcut methods like "assertBodyEvaluated(int numberOfTimes)" 
are imaginable, but I can't see an easy way around the Interceptor usage 
when you need to do assertions about the pageContext "inside the body", 
as in [Example 3]. So the idea would be to allow chaining of 
interceptors (currently only one is allowed), and have the shortcut 
methods implicitly insert specialized interceptors into the chain. Test 
case specific interceptors defined as anonymous inner classes would 
still be allowed for advanced tests.

[I'm a bit uncertain about the "assertXXX" naming scheme, maybe 
"expectXXX" would be better?]

Second, the testing of tag collaboration is pretty hard to accomplish 
using the current strategy. Ideally, I'd like to allow nesting of 
JspTagLifecycle instances, to be able to write tests like this:

     ChooseTag chooseTag = new ChooseTag();
     JspTagLifecycle chooseLifecycle =
       new JspTagLifecycle(pageContext, chooseTag);

     WhenTag whenTag = new WhenTag();
     JspTagLifecycle whenLifecycle =
       new JspTagLifecycle(pageContext, whenTag);
     whenTag.setTest("false");
     whenLifecycle.assertBodySkipped();

     OtherwiseTag otherwiseTag = new OtherwiseTag();
     JspTagLifecycle otherwiseLifecycle =
       new JspTagLifecycle(pageContext, otherwiseTag);
     otherwiseLifecycle.assertBodyEvaluated();

     chooseLifecycle.addNestedTag(whenLifecycle);
     chooseLifecycle.addNestedTag(otherwiseLifecycle);
     chooseLifecycle.invoke();

This looks a bit complicated, but actually isn't ;-) ... Basically, when 
a JspTagLifecycle has nested tags, their lifecycle will be invoked when 
the body of the enclosing tag is evaluated. There could also be an 
addNestedText(String) method, that would add simple template text to the 
body content of the enclosing tag. All nested elements would be invoked 
in the order they have been added.

                                   -----

So these are the thoughts I'm playing with. I'd love to get some 
feedback: Is this something that would simplify taglib testing for you? 
Any recommandations for the API? Concerns about the general approach? etc.

[BTW, I'm still waiting for karma to commit a couple of fixes to the 
version in Cactus CVS, so if you want to check it out, be warned that
there are a couple of problems]

-- 
Christopher Lenz
/=/ cmlenz at gmx.de


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


Re: JspTagLifecycle: Testing JSP tag libraries with Cactus

Posted by Christopher Lenz <cm...@gmx.de>.
Hi Glenn,

Glenn Nielsen wrote:
> Christopher Lenz wrote:
> 
>> Hi again,
>>
>> considering the overwhelming response to this mail (not ;-) ), I'm 
>> gonna add some more:
>>
> 
> The taglib lists are a bit slow, and this is a four day holdiay in the 
> states.
> So please be patient. :-)

No problem :-)

> I am aware of Cactus but haven't had time to play with it yet. It is on 
> my list
> of technologies I want to research and possibly incorporate into 
> development/testing
> where I work. :-)
> 
> It looks like the test suite uses a servlet container but not the 
> container's JSP
> engine. JSP custom tags and their behaviour is very tightly coupled to 
> the JSP
> engine the custom tag lib is running within.  Things like JSP engine 
> custom tag
> pooling, etc. can have a big impact on whether tags work correctly.  I 
> wonder how
> useful a test suite like this would be when it doesn't also test the 
> container
> JSP engine.

Yeah, unfortunately it's impossible to use the container's JSP engine 
without actually supplying JSP pages. And while I agree that custom tags 
are in some aspects tightly coupled to the JSP implementation, there is 
also a specification that defines how a JSP tag is to be handled by the 
JSP compiler/runtime. And IMHO much of the confusion about how a JSP 
engine should operate is in the area of scripting variables. Tag 
pooling/reuse, as you note, is also problematic, but out of scope for 
the JspTagLifecycle helper (currently).

The JspTagLifecycle class focusses on JSP1.2 and purposely doesn't deal 
with scripting variables of any kind. It just implements the lifecycle 
diagrams that are in the JSP specification/javadocs, so that the test 
writer doesn't need to type in the same code again and again. If you 
like, check out the code, it's really simple (method invokeInternal(), 
at the bottom):

http://cvs.apache.org/viewcvs.cgi/*checkout*/jakarta-cactus/framework/src/java/j2ee13/org/apache/cactus/extension/jsp/JspTagLifecycle.java?rev=HEAD&content-type=text/plain

> Setting up test cases using actual JSP pages then making sure you get 
> back the
> correct response is much more complete testing of both the tags and the JSP
> engine IMHO.

Cactus tests are by their very nature on the border between unit tests 
and integration tests. When you use JspTagLifecycle for your tests, 
you're still doing unit tests, i.e. you're testing by invoking the code 
that would be called in the "real" system in a similar way. But you're 
also testing integration with the container because you're using the 
actual implementations of PageContext, HttpServletRequest, etc etc.

Testing actual JSP pages by checking the results returned to the client 
is functional testing, and is by definition and by nature less 
fine-grained, because you're viewing the system from the outside. 
Setting up tons of JSP pages just to test all the variations of usage of 
a <c:set>-tag (for example) is quite a hassle, and then you still need 
to parse the results in some way, as well as get the TLD right before 
the tests. Certainly there are techniques to automate or at least 
support the process, but it's still more work than plain JUnit tests 
(which Cactus tests are, in essence). And test frameworks are all about 
making testing easier :-)

All that said, there's definitely room here for both Cactus tests as 
well as for functional, HttpUnit-style tests (Cactus even offers easy 
integration with HttpUnit, so you can stay within one testing framework 
;-) ). I estimate that using the Cactus JspTestCase + JspTagLifecycle 
method will give you about 90% test coverage for your JSP taglibs, and 
then you can still add the remaining 10% by writing a couple of JSPs 
with heavy tag reuse provocation etc.

Thanks for the feedback :-)

-- 
Christopher Lenz
/=/ cmlenz at gmx.de


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


Re: JspTagLifecycle: Testing JSP tag libraries with Cactus

Posted by Glenn Nielsen <gl...@mail.more.net>.
Christopher Lenz wrote:
> Hi again,
> 
> considering the overwhelming response to this mail (not ;-) ), I'm gonna 
> add some more:
> 

The taglib lists are a bit slow, and this is a four day holdiay in the states.
So please be patient. :-)

I am aware of Cactus but haven't had time to play with it yet. It is on my list
of technologies I want to research and possibly incorporate into development/testing
where I work. :-)

It looks like the test suite uses a servlet container but not the container's JSP
engine. JSP custom tags and their behaviour is very tightly coupled to the JSP
engine the custom tag lib is running within.  Things like JSP engine custom tag
pooling, etc. can have a big impact on whether tags work correctly.  I wonder how
useful a test suite like this would be when it doesn't also test the container
JSP engine.

Setting up test cases using actual JSP pages then making sure you get back the
correct response is much more complete testing of both the tags and the JSP
engine IMHO.

Regards,

Glenn


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


Re: JspTagLifecycle: Testing JSP tag libraries with Cactus

Posted by Christopher Lenz <cm...@gmx.de>.
Hi again,

considering the overwhelming response to this mail (not ;-) ), I'm gonna 
add some more:

The version now in CVS does support some IMHO pretty elegant testing of 
JSP 1.2 based tag libraries. For an example of what is possible (and how 
easily), look at the following test suite:

http://cvs.apache.org/viewcvs.cgi/*checkout*/jakarta-cactus/sample-servlet/src/unit/j2ee13/org/apache/cactus/unit/TestJspTagLifecycle.java?rev=HEAD&content-type=text/plain

A bit down in the testsuite (starting with testOutTag()) are about 15 
tests for the Jakarta-Taglibs implementation of JSTL-Core.

<hint>This could be used as a starting point for a real unit test suite 
for taglibs-standard... or am I the only one who finds it kinda 
disturbing that there are no tests, at least not publically 
available?</hint>. ;-)

Christopher Lenz wrote:
[...]
> As some of you might have noticed, I've recently submitted a new 
> extension class to Cactus that is supposed to help with the testing of 
> JSP tag libraries.
[...]

-- 
Christopher Lenz
/=/ cmlenz at gmx.de


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