Skip to main content

Introduction to Tag Unit, Part 1

July 5, 2004

{cs.r.title}








Contents
Unit Testing and J2EE
Unit Testing JSP Custom Tags
JSP Custom Tags Aren't Standalone Classes
Unit Testing JSP Custom Tags with TagUnit
Getting Started
Summary

JSP custom tags allow developers to abstract complex code out
of a JSP page and into reusable components. JSP custom tags are not,
however, standalone classes, and therefore cannot be fully tested with
tools like JUnit. Once you think of custom tags as
components in their own right, you see that they should be tested --
and tested as components. This pair of articles will introduce TagUnit -- an easy-to-use, open source testing tool that makes it possible to comprehensively
test JSP tags.

Unit Testing and J2EE

Unit testing is the process of testing a particular piece of code
by isolating that code and concentrating your tests on the expected
operation of that code. Particularly with automated tools, unit
testing gives you not only a level of confidence that your code works
as expected, but also gives you a way to regression test your code
when changes are introduced tomorrow, next week, or in years to come.
This is very important for code stability and the freedom to refactor as
necessary. As developers, unit-testing efforts are focussed at the method,
class, or component level.

The unit-testing tool of choice for most Java developers is JUnit, which is a very simple testing framework that allows you to build up test cases consisting of
assertions. These test cases typically focus on a specific class and
can be brought together to form a test suite that might cover anything
from a logical grouping of classes to your entire application. While
JUnit is pretty much the de facto testing framework, the inherent
complexities in building J2EE applications that execute inside of a J2EE
application server pose new problems. For example, it's much harder to
test components such as Enterprise JavaBeans or Java servlets without
all of the plumbing and infrastructure that J2EE provides us as
developers.

Thankfully, other tools and frameworks have been created to
address some of these issues. As an example, we have Cactus, which provides a way to run JUnit tests inside of an application server; several mock-object
libraries (for example, MockObjects) to help us stub out
dependencies that our J2EE code has upon the underlying application server; and a few functional testing tools such as HttpUnit that help us to prove the
function of the system from a black-box perspective. In effect, with a
combination of these tools, it's possible to achieve a fairly high
degree of code coverage in your testing. However, one area in which people
struggle or forget to test is that of JSP custom tags.

Unit Testing JSP Custom Tags

Put simply, custom tags are a way of wrapping up recurring
presentation logic into reusable components. If you look at a tag
library such as the JavaServer Pages Standard Tag Library (JSTL), it has a number of useful tags that simplify the process of writing JSP pages. It has tags that
iterate over collections and arrays, tags that output information from
JavaBeans, tags that format dates, and so on. In addition to using
pre-packaged tags, you may find yourself writing some of your own, or
extending the functionality provided by libraries such as JSTL. In
either case, how would you test that they function as expected?

One solution is to use JUnit and test the tag-handler classes as
if they were standalone Java classes, testing each and every method in
isolation. The problem with this approach is that custom tags are
designed to be executed inside of a J2EE web container and ultimately
have dependencies on classes such as PageContext and
JspWriter, the implementations of which are provided by
the JSP container vendor. This is not a new problem, and a common
solution is to use one of the many mock-object frameworks to satisfy
these dependencies by using dummy (mock) implementations. Mock objects
work well but don't test the interaction between your code and a real
implementation. An alternative approach is to use Cactus, a framework
that allows you to build and execute tests inside of a real J2EE web
container so that your code interacts with real objects. All of
these solutions will work, and you may even be able to achieve 100 percent
code coverage from your testing, but there is one point that we've
not yet considered.

JSP Custom Tags Aren't Standalone Classes

Custom tags are more than standalone Java classes; they are components in their own
right. Alongside each tag handler class is a tag definition inside of a
tag library descriptor (TLD) file that defines the name of each tag,
the attributes it can take, what type of body content is permitted,
etc. At development time, you use custom tags inside of your JSPs through
an XML syntax and not by directly instantiating the tag handler
classes. For all intents and purposes, this XML syntax defines the
component interface to any given tag. Because tags are used in this
way, it makes most sense to test them in this way, too. In other words,
custom tags are components and therefore need to be tested at that
level, in the way that they would normally be used from within a JSP
page.

Having established that custom tags are components, it now starts
to become clear why you might want to test them as components rather
than as standalone classes. Imagine that someone in your team has
written a service (something like an EJB or web service) and told you
that he or she has only tested the implementation, without using the public
interface. While this might give you some confidence, you'd probably like to know that you
can successfully use the implementation via its API. In addition to
this, the people that will use your tags will often try to use them
in weird and wonderful ways that you had never imagined, so some degree
of testing is certainly beneficial, particularly if you are building
and releasing tags for use by other teams.

A final reason why it's good to test custom tags as components is
because of the often complex interactions that they have with the web
container. A great deal of work has gone into JSP 2.0 around
simplifying the custom tag programming model, although the actual
lifecycle of tags is still frequently misunderstood, particularly
around optional features of the JSP specification such as tag handler
instance pooling and cleaning up state between invocations.
Unfortunately for us, each J2EE server vendor has a slightly different
approach to implementing the specification and this can make it harder
to produce truly portable tag handler implementations. Having an
in-container test suite makes this particularly easy to assert.

Unit Testing JSP Custom Tags with TagUnit

Now that we've looked at why we should test custom tags as
components, we need to look at how this is possible. Earlier on,
we briefly discussed some of the options that are available for
testing custom tags, namely with tools such as JUnit, Cactus, and mock
objects. Another possible solution that wasn't mentioned is that you
could build a JSP-based test harness that contained a number of tags
and use something like HttpUnit to perform assertions that the output
generated is as expected. Unfortunately, this doesn't take into account
the fact that some tags don't produce HTML.

The motivation behind TagUnit is to treat tags as the units from
which JSP pages are built and to provide a way in which they can be
tested in isolation from the application-specific pages on which they
will ultimately be used. Since tags are dependent on the features
provided by the JSP container in which they run, it makes sense to
test them from within the JSP container. This approach provides a
number of benefits.

  1. Although the individual tag handler methods can be tested as
    a part of the unit-testing process, this still doesn't guarantee that
    they will work inside of the container when deployed. Testing tags
    inside of a container addresses this risk up front.

  2. Custom tags may have several side effects that are much more easily tested when
    they are running inside of a container. These include the introduction of
    scripting variables, manipulation of page-context attributes,
    iteration and manipulation of body content, and so on.

  3. Having a suite of in-container tests means that you can take those tests and
    run them inside of another container to check that you aren't relying on
    container-specific features or subtleties in the specific vendor's
    implementation of the JSP specification. Of course, on the flip side,
    it does mean that you can test such features if you need to make use
    of them.

So then, what exactly is TagUnit? Essentially, it's a web
application consisting of a number of JSPs and tag libraries that you
can use to test your own tag libraries. In the same way that JUnit
lets you build up test cases containing assertions for standalone Java
classes, TagUnit allows you to do the same for testing tag libraries.
TagUnit provides a number of assertion tags, and these are used to
perform the actual tests, with multiple JSP pages being used to build
up the test cases.

Getting Started

For the purpose of this article, let's say that we would like to
test the core taglib from the Jakarta Taglibs implementation of the JSTL, a taglib that many people will be aware of and have experience with. Assuming that you already have a container compatible with JSP 1.2/Servlet 2.3, such as Tomcat 4.1.x, the
following steps describe how to get started with TagUnit. Throughout
the instructions, we'll assume that you're using a default Tomcat
install under $TOMCAT_HOME and running on the standard
port of 8080. The steps to getting TagUnit up and running are as
follows.

  1. First of all, you'll need to download a copy of the JSTL (I'm using v1.0.5) and TagUnit (I'm using v1.0.1).

  2. Inside of the TagUnit distribution is a template web application called tagunit-blank.war.
    Because we're going to add to this webapp later, you'll need to deploy
    it to your JSP container in the exploded format. If you're using
    Tomcat, simply create a directory called tagunit-blank
    underneath $TOMCAT_HOME/webapps and extract the contents
    of the .war file into this directory.

  3. At this point, if you
    would like to test the deployment, restart your server and point your
    browser to http://localhost:8080/tagunit-blank/. If all is well, you will see a page containing a number of test results for the TagUnit tags themselves.

  4. The next step is to deploy your tag library into the tagunit-blank web
    application. With most tag libraries, this just involves copying one
    or more .jar files into WEB-INF/lib. With JSTL, you'll
    need to copy standard.jar and jstl.jar from
    the lib directory of the JSTL distribution into the
    WEB-INF/lib directory of the web application.

  5. With the tags deployed, we now need to tell TagUnit about them. To
    do this, open up the /test/index.jsp file from the web
    application into your favorite text editor and modify the content to
    be the following.

    <%@ taglib uri="http://www.tagunit.org/tagunit/core"
    prefix="tagunit" %>

    <tagunit:testTagLibrary uri="/test/jstl-core">
    <tagunit:tagLibraryDescriptor jar="standard.jar" name="c.tld"/>
    </tagunit:testTagLibrary>

    The first line imports the TagUnit tags, making them available for use, while the final three
    tell TagUnit that our tests will reside underneath /test/jstl-core and that we're testing the tag library
    deployed in [WEB-INF/lib/]standard.jar, described by the
    TLD file called c.tld inside of that .jar file.

Although we've not even started writing tests to exercise the tags
yet, we are already in a position to let TagUnit perform some
preliminary testing of its own, simply based upon the fact that
TagUnit has been told about a tag library. If you restart the server
at this point and point your browser to http://localhost:8080/tagunit-blank/, you will see some test results for the JSTL core tag library, as shown in Figure 1.

Figure 1
Figure 1. Test results for the JSTL core tag library

The block of color at the top of the page gives a quick
indication about the status of the tests -- green for all passes,
orange for warnings, and red for failures/errors. For the moment, don't
be alarmed that we have several warnings. This is just TagUnit's way
of telling you that you've not actually written any tests yet. If you
scroll down the page, you should see that each and every tag in the
JSTL core tag library is listed. Each of these has its own test
status and nested underneath are the tests that have been executed. By
default, TagUnit runs a set of automatic tests against each custom tag
in the tag library based upon the information provided by the TLD
file. These tests assert that:

  • The tag handler class is loadable from the classpath, can be
    instantiated and implements the basic
    javax.servlet.jsp.tagext.Tag interface.
  • As above
    but with the javax.servlet.jsp.tagext.TagExtraInfo class,
    if applicable.
  • A getter method is available for each tag
    attribute and the parameter type is loadable from the classpath.

Even if you were to never actually write a test with TagUnit,
these automatic tests are useful in their own right, giving you
confidence that you've not forgotten to implement any of the basic tag
handler contract; for example, helping to ensure that the attributes on the
tag handler match those that are defined in the TLD file.
Additionally, they help prevent situations where tags are packaged
and/or deployed incorrectly.

Summary

One of the conclusions that many developers come to when building
J2EE applications is that a single testing tool doesn't always provide
the ability to perform testing to cover the complete
codebase. Tools like JUnit certainly allow you to unit test a high
percentage of the codebase, but J2EE applications are, by nature, constructed of
multiple higher-level components. This article introduced TagUnit and
showed why and how you should consider unit testing your custom tags. TagUnit complements
other testing tools and can be thought of as another tool in your toolbox
on your quest to thoroughly test your J2EE applications. In the next
article, we'll look at how to build up a test suite with TagUnit to test
the functionality provided by custom tags.

Simon Brown is a technical architect, based in London, who likes to get his hands dirty and write the code after he's drawn the boxes.
Related Topics >> JSP   |   Testing   |