Save This Page
Home » cactus-1.8.0-src » org.apache.cactus.extension.jsp » [javadoc | source]
org.apache.cactus.extension.jsp
public final class: JspTagLifecycle [javadoc | source]
java.lang.Object
   org.apache.cactus.extension.jsp.JspTagLifecycle
Convenience class that supports the testing of JSP tag by managing the tag's lifecycle as required by the JSP specification.

This class is basically a stub implementation of the tag management facilities that an actual JSP container would provide. The implementation attempts to follow the specification as closely as possible, but the tag handling functionality of real JSP implementations may vary in some details.

Although this class works quite well when used in the test methods of a JspTestCase , it can also safely be used outside of the Cactus testing framework, for example when following a mock objects approach.

Testing Simple Tags

This is how you would use this class when testing the <c:set>-tag of the JSTL reference implementation:

SetTag tag = new SetTag();
JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
tag.setVar("name");
tag.setValue("value");
lifecycle.invoke();
assertEquals("value", pageContext.findAttribute("name"));
The order is important:
  1. Instantiation of the tag under test
  2. Instantiation of the lifecycle helper, passing in the page context and the tag instance
  3. Set the tag's attributes
  4. Start the tag's lifecycle by calling JspTagLifecycle.invoke()
  5. Make assertions

Adding Expectations to the Lifecycle

JspTagLifecycle features a couple of methods that let you easily add expectations about the tag's lifecycle to the test. For example, the method expectBodySkipped() can be used to verify that tag's body is not evaluated under the conditions set up by the test:

IfTag tag = new IfTag();
JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
tag.setTest("false");
lifecycle.expectBodySkipped();
lifecycle.invoke();

An example of a more sophisticated expectationion is the #expectScopedVariableExposed(String, Object[]) method, which can verify that a specific scoped variable gets exposed in the body of the tag, and that the exposed variable has a specific value in each iteration step:

ForEachTag tag = new ForEachTag();
JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
tag.setVar("item");
tag.setItems("One,Two,Three");
lifecycle.expectBodyEvaluated(3);
lifecycle.expectScopedVariableExposed(
"item", new Object[] {"One", "Two", "Three"});
lifecycle.invoke();

Custom Expectations

In some cases, using the expectations offered by JspTagLifecycle does not suffice. In such cases, you need to use custom expectations. You can add custom expectations by creating a concrete subclass of the Interceptor class, and adding it to the list of the tag lifecycles interceptors through addInterceptor() :

ForEachTag tag = new ForEachTag();
JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
tag.setVarStatus("status");
tag.setBegin("0");
tag.setEnd("2");
lifecycle.addInterceptor(new JspTagLifecycle.Interceptor() {
public void evalBody(int theIteration, BodyContent theBody) {
LoopTagStatus status = (LoopTagStatus)
pageContext.findAttribute("status");
assertNotNull(status);
if (theIteration == 0) {
assertTrue(status.isFirst());
assertFalse(status.isLast());
}
else if (theIteration == 1) {
assertFalse(status.isFirst());
assertFalse(status.isLast());
}
else if (theIteration == 2) {
assertFalse(status.isFirst());
assertTrue(status.isLast());
}
}
});
lifecycle.invoke();

Specifying Nested Content

JspTagLifecycle let's you add nested tempate text as well as nested tags to the tag under test. The most important use of this feature is testing of collaboration between tags, but it also allows you to easily check whether a tag correctly handles its body content.

The following example demonstrates how to add nested template text to the tag, and how to assert that the body was written to the HTTP response on the client side:

public void testOutTagDefaultBody() throws JspException, IOException {
OutTag tag = new OutTag();
JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
tag.setValue(null);
lifecycle.addNestedText("Default");
lifecycle.expectBodyEvaluated();
lifecycle.invoke();
}
public void endOutTagDefaultBody(WebResponse theResponse) {
String output = theResponse.getText();
assertEquals("Default", output);
}

In sophisticated tag libraries, there will be many cases where tags need to collaborate with each other in some way. This is usually done by nesting such tags within eachother. JspTagLifecycle supports such scenarios by allowing you to add nested tags to an existing tag lifecycle. The nested tags can than be decorated with expectations themselves, as you can see in the following example:

ChooseTag chooseTag = new ChooseTag();
JspTagLifecycle chooseLifecycle =
new JspTagLifecycle(pageContext, chooseTag);
WhenTag whenTag = new WhenTag();
JspTagLifecycle whenLifecycle =
chooseLifecycle.addNestedTag(whenTag);
whenTag.setTest("false");
whenLifecycle.expectBodySkipped();
OtherwiseTag otherwiseTag = new OtherwiseTag();
JspTagLifecycle otherwiseLifecycle =
chooseLifecycle.addNestedTag(otherwiseTag);
otherwiseLifecycle.expectBodyEvaluated();
chooseLifecycle.invoke();
The code above creates a constellation of tags equivalent to the following JSP fragment:
<c:choose>
<c:when test='false'>
<%-- body content not significant for the test --%>
</c:when>
<c:otherwise>
<%-- body content not significant for the test --%>
</c:otherwise>
</c:choose>

Nested Class Summary:
abstract public static class  JspTagLifecycle.Interceptor  Abstract class for intercepting the tag lifecycle. You can override any of the methods to insert expectations about the tag's behaviour while it is being executed. 
Field Summary
protected  PageContext pageContext    The JSP page context. 
Constructor:
 public JspTagLifecycle(PageContext thePageContext,
    Tag theTag) 
    Constructor.
    Parameters:
    thePageContext - The JSP page context
    theTag - The JSP tag
Method from org.apache.cactus.extension.jsp.JspTagLifecycle Summary:
addInterceptor,   addNestedTag,   addNestedText,   expectBodyEvaluated,   expectBodyEvaluated,   expectBodySkipped,   expectScopedVariableExposed,   expectScopedVariableExposed,   invoke
Methods from java.lang.Object:
equals,   getClass,   hashCode,   notify,   notifyAll,   toString,   wait,   wait,   wait
Method from org.apache.cactus.extension.jsp.JspTagLifecycle Detail:
 public  void addInterceptor(JspTagLifecycle.Interceptor theInterceptor) 
    Adds an interceptor to the interceptor chain.
 public JspTagLifecycle addNestedTag(Tag theNestedTag) 
    Adds a nested tag. The tag will be invoked when the body content of the enclosing tag is evaluated.
 public  void addNestedText(String theNestedText) 
    Adds template text to nest inside the tag. The text will be printed to the body content when it is evaluated.
 public  void expectBodyEvaluated() 
    Adds the expectation that the tag body must be evaluated once in the course of the tags lifecycle.
 public  void expectBodyEvaluated(int theNumIterations) 
    Adds the expectation that the tag body must be evaluated a specific number of times in the course of the tags lifecycle.
 public  void expectBodySkipped() 
    Adds the expectation that the tag body must be skipped. Essentially, this expectation verifies that the tag returns SKIP_BODY from doStartTag().
 public  void expectScopedVariableExposed(String theName,
    Object[] theExpectedValues) 
    Adds a special expectation that verifies that a specific scoped variable is exposed in the body of the tag.
 public  void expectScopedVariableExposed(String theName,
    Object[] theExpectedValues,
    int theScope) 
    Adds a special expectation that verifies that a specific scoped variable is exposed in the body of the tag.
 public  void invoke() throws IOException, JspException 
    Invokes the tag with the provided interceptor. The tag should have been populated with its properties before calling this method. The tag is not released after the tag's lifecycle is over.