Skip to main content

Introduction to Tag Unit, Part 2

{cs.r.title}








Contents
Test Suites, Test Cases, and Assertions
Testing the JSTL forEach
Tag
Testing the Interface
Testing Fixed Loops
Other Features
Summary

In Introduction to TagUnit: Part 1, we looked at
some of the various ways in which custom tags can be tested before
demonstrating some of the basic features provided by TagUnit--an open
source testing tool specifically aimed at JSP custom tags. In this
article we'll complete the story by looking at some examples of how
tests can be written with TagUnit.

Test Suites, Test Cases, and Assertions

If you have experience with other testing frameworks, the
conventions and frameworks of TagUnit will feel familiar. In JUnit we have test suites, test cases, and
assertions. Likewise in TagUnit. Tests are written as assertions and
these tests are grouped together to form a larger test case. Test cases
are then assembled to form a test suite. The key difference between
TagUnit and most other testing tools is that tests within TagUnit are
written as JSP pages rather than Java classes. In TagUnit, tests are
broken down as follows.

  • An assertion is written as a custom tag.
  • A test consists of one or more assertions, written inside a JSP page.
  • A test case consists of many tests and is a grouping of all the tests for a given custom tag.
  • A test suite is the collection of all test cases for a given tag library.

With this basic understanding of the test structure we can now go on and write some tests.

Testing the JSTL forEach Tag

Assuming that you followed the setup instructions in the previous
article
, you should be able to point your browser to http://localhost:8080/tagunit-blank/ and see the results for the automatic tests that are
performed on the JSTL core tag library. To illustrate how to use
TagUnit, let's write a few tests for the JSTL forEach tag
that provides iteration facilities over a number of different object
types, including collections and arrays.

The first thing we need to do is create the directories in which
the tests will reside. The way TagUnit works is that there is a
directory-per-tag library being tested (a test suite) and
subdirectories underneath these for each tag (a test case) that is
being tested. In the index.jsp page we introduced in the first article, we
used the following piece of code to tell TagUnit which tag library we
would like to test.

<%@ 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. 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 that JAR file. The
uri attribute of the testTagLibrary tag
describes a path underneath this web application where the tests for
the JSTL core tag library will be written. You need to create this
directory and a further subdirectory for each tag that you would like
to test. In this case, create a subdirectory called
forEach to hold the tests for the forEach
tag. The resulting web application structure is shown in figure 1.

Figure 1. Web application structure

Figure 1. Web application structure

With the
directory structure in place we can write some
tests. As mentioned earlier, assertions are custom tags and a test
consists of one or more assertions, written as a JSP page. To follow
the JUnit convention, these JSPs must be named testX.jsp,
where X can be any arbitrary string. Therefore, in the same way that JUnit lets you
have more than one test inside a test case by defining multiple
testX() methods, TagUnit lets you define one or more
testX.jsp pages so that tests can be grouped and/or split
as necessary.

Testing the Interface

Many
of the current crop of IDEs are able to perform JSP validation either
incrementally or during the build process. From a JSP tag perspective,
this is a very useful feature in that it lets you know when you've used
the wrong set of attributes for a given tag, or
specified body content for an empty tag, and so on. More commonly, a developer will only discover
that a tag has been used incorrectly at runtime, when the page is
requested. During the development cycle, another potential problem with
using tags is that another member of the team might change the tag
definition that includes the set of attributes and body content. In the first article, we said that the set of attributes and body content can be
thought of as the interface of the tag. When you
change a Java interface, you will generally expose this type of error
at compile time. This generally isn't the case with JSP tags. One way to address
this problem is to write a test that performs assertions based upon the
interface, or specification, of that tag. With TagUnit this is
straightforward.

The first step in writing a TagUnit test is to create a JSP page
underneath the appropriate directory that follows the previously
mentioned naming standard. Since we're going to be testing the
specification of the forEach tag, we'll create a JSP page
called testSpecification.jsp underneath the
forEach directory. We'll be using the TagUnit tags to
perform assertions so the following taglib directive should be placed
at the top of the page.

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

Next are the assertions.

<tagunit:assertBodyContent name="JSP"/>

<tagunit:assertAttribute name="var" required="false"
rtexprvalue="false"/>
<tagunit:assertAttribute name="items" required="false"
rtexprvalue="false"/>
<tagunit:assertAttribute name="varStatus" required="false"
rtexprvalue="false"/>
<tagunit:assertAttribute name="begin" required="false"
rtexprvalue="false"/>
<tagunit:assertAttribute name="end" required="false"
rtexprvalue="false"/>
<tagunit:assertAttribute name="step" required="false"
rtexprvalue="false"/>

<tagunit:assertInterface
name="javax.servlet.jsp.jstl.core.LoopTagSupport"/>

The TagUnit documentation
contains a full reference of the assertions available, but here we'll
briefly explain their purpose. The first tag
(assertBodyContent) performs an assertion based upon the
body content of the tag as defined in the TLD file, checking that the
value specified matches. The second tag (assertAttribute)
tests that the given attribute is defined for the tag and, optionally,
has the specified characteristics. In this example, we perform
assertions for the entire set of attributes for the
forEach tag, asserting that they are not required and
don't accept runtime expressions. Although not the case here, the
assertNoAttributes tag can be used to test that the custom
tag under test doesn't declare any attributes in the TLD file. The
final tag (assertInterface) tests that the tag handler
implements the given (fully qualified) class or interface name. For
tags that allow extension and/or cooperation, this is an important part
of the contract because other tags generally rely on casting tag
handler instances at runtime, something that's hard to pick up during a
standard build cycle. Writing a test allows you to see when a tag
handler stops implementing the given interface.

Testing Fixed Loops

The forEach tag has the ability to iterate over a number of
different types of collections and arrays, while also being able to
provide a fixed number of iterations, like a traditional
for loop, by specifying the
begin and end attributes. Optionally, the
var attribute allows us to specify the name of a variable
that will be exposed and continuously updated with the next item in the
iteration. The following example shows a fixed loop that will output 123 (we're using the JSTL core
out tag to output the the value of i).

<c:forEach var="i" begin="1" end="3">
   <c:out value="${i}"/>
</c:forEach>

So, if we were the developer of this tag, how would we test this?

In addition to the assertions that we've already seen, TagUnit provides
other assertions that can be used to compare output and the
availability of scoped objects. To start with, let's create a JSP
called testFixedLoop.jsp underneath the
forEach directory again and start off by including the
various taglib directives that we will need for our tests.

<%@ taglib uri="http://www.tagunit.org/tagunit/core"
prefix="tagunit" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core"
%>

Since we're going to be using the JSTL core tags, we need to import
these too this time around. Next, let's write a simple test for the
forEach tag that proves that it can correctly perform
three iterations.

<tagunit:assertEquals name="Fixed loop with static body
content">
  <tagunit:expectedResult>TestTestTest</tagunit:
expectedResult>
  <tagunit:actualResult>
    <c:forEach begin="1" end="3">Test</c:forEach>
  </tagunit:actualResult>
</tagunit:assertEquals>

In this example we're using the assertEquals tag to
indicate that we would like to perform a comparison. As with JUnit, we
have an expected result and an actual result, which are wrapped up
between the expectedResult and actualResult
tags, respectively. At runtime, the TagUnit tags consume any content that is output within their body content to perform the comparison. That's
all there is to building simple tests, and although the XML can seem a
little verbose the semantics of the tests are similar to those written
with JUnit.

Next, to show something a little different, let's write a test
for the var attribute that we mentioned earlier in a file
called testVarAttributeExposed.jsp. In this test we'll
create an array of strings and let the forEach tag iterate
over them using the items attribute. By specifying the
var attribute, the forEach tag will expose
each element of the array in turn.

<%@ taglib uri="http://www.tagunit.org/tagunit/core"
prefix="tagunit" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>

<%
   String strings[] = new String[] {"A string"};
   pageContext.setAttribute("strings", strings);
%>
<c:forEach var="item" items="${strings}">
   <tagunit:assertPageContextAttribute name="item"
type="java.lang.String" value="A string"/>
</c:forEach>

Here the assertPageContextAttribute tag is being used to
assert for the existence of a page scoped object with the given name,
type, and value. Exposing objects is another common usage pattern for
custom tags and something that is also worth testing.

Other Features

In addition to the assertEquals tag, TagUnit provides
other comparison-based assertions, including
assertNotEquals, assertContains, and
assertMatches. The latter two are useful when you are testing
custom tags that output a large amount of content and only want to test
for the presence of key information. In the previous example you
probably noticed that we created an array of strings and placed these
into the page scope. If this type of logic is common to many tests, we
can write a JSP page called setUp.jsp in the same way that
we can write a setUp() method in a JUnit testcase.
Similarly, we can write a page called tearDown.jsp. Some
final points to mention are that TagUnit has integration with Ant so
that TagUnit tests can be executed automatically, as part of a larger
build process and it's easy to get code coverage information for your custom tags with tools like Clover.

Summary

Custom tags typically encapsulate common presentation logic on JSP
pages and generally have some effect on how the pages themselves are
rendered. Some tags output markup while some retrieve information,
ready for it to be displayed by other components. Without a complete
JSP environment, testing tags is difficult and this is the primary
reason that TagUnit was created. Using the tool we can easily build up
test suites for JSP tags that can be deployed and executed in one or
more JSP containers with ease, which is also useful for testing the
portability of tags between vendor implementations.

Following on from the first article, this article shows how to start
building tests with TagUnit. Tests are written as JSP pages and by
using the various assertion tags, complex test cases and test suites
can be built up. In conjunction with other testing tools, TagUnit
provides a way to help test more of your J2EE web applications. With
TagUnit, custom tags can be tested in the same way that page authors
will use them--from JSP pages.

Related Topics >> JSP   |   Testing   |