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><c:out></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("<value/>", output);
}
Example 2 (conditional)
-----------------------
/**
* Tests the conditional tag <c:if> 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 <c:forEach> 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>