| <?xml version="1.0"?> |
| <document> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to you under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| <properties> |
| <title>Shale Test Framework</title> |
| </properties> |
| |
| <body> |
| |
| <section name="Shale Test Framework"> |
| <a name="test"/> |
| |
| <a name="test-introduction"/> |
| <subsection name="Introduction"> |
| |
| <p>Modern application development processes have embraced the idea of |
| <em>unit testing</em> as an integral step in creating high quality |
| software. In the Java world, a popular framework for building and |
| executing such unit tests is the <a href="http://junit.org">JUnit</a> |
| framework. It is straightforward for an application developer to |
| create a corresponding <em>test case</em> class for each class in the |
| application itsef, and ensure that the tests contained in the test case |
| get executed as part of the normal application build process.</p> |
| |
| <p>One of the tenets of unit testing is that a test case should focus |
| <em>only</em> on the methods of the class under test, in isolation from |
| related application classes, or APIs provided by any container that the |
| class under test might be installed into at runtime. But, how do you |
| test an application class that has dependencies on such APIs (such as |
| depending on the Servlet API to provide an <code>HttpServletRequest</code> |
| object representing an incoming HTTP request)?</p> |
| |
| <p>A popular answer to this dilemma is to utilize a library of |
| <em>mock objects</em> -- classes that implement and emulate the container |
| APIs, but still run in the isolated environment of a JUnit test case. |
| Shale provides mock object implementations for its own features, as |
| well as features of the underlying container (Servlet |
| and JavaServer Faces) environment. In addition, convenient base classes |
| are provided to make it very easy to build your own test cases utilizing |
| these mock objects. This library is used to create unit tests for Shale |
| components itself, but it is primarily focused on making it easy to |
| build unit tests for application classes such as |
| <code>ViewController</code>s.</p> |
| |
| </subsection> |
| |
| <a name="test-services"/> |
| <subsection name="Provided Services"> |
| |
| <p>The Shale Test Framework provides mock object libraries, plus base |
| classes for creating your own JUnit <code>TestCase</code>s.</p> |
| |
| <p>Mock objects are provided in package <code>org.apache.shale.test.mock</code> |
| for the following container APIs:</p> |
| <ul> |
| <li>JavaServer Faces</li> |
| <li>Servlet</li> |
| </ul> |
| <p>These mock object classes implement the majority of the functionality |
| defined by the container API Javadocs (although some methods currently |
| throw <code>UnsupportedOperationException</code>). In addition, many |
| of these classes support public methods, outside of the defined API, |
| for configuring the object in a test environment. For example, |
| <code>MockServletContext</code> includes <code>addInitParameter()</code> |
| and <code>setDocumentRoot()</code> methods, to add context initialization |
| parameters to the set returned via <code>getInitParameter()</code> and |
| <code>getInitParameterNames()</code>, and to establish the base directory |
| for resolving servlet context resources, respectively.</p> |
| |
| <p>The <code>org.apache.shale.test.base</code> package contains abstract |
| base classes that wire together instances of the various container API |
| mock objects, in a manner similar to the way they would become available |
| at runtime. The following base classes are available:</p> |
| <ul> |
| <li><code>AbstractJsfTestCase</code> - Base class for unit tests that |
| require Servlet and JavaServer Faces objects to be available.</li> |
| <li><code>AbstractViewControllerTestCase</code> - Extension of |
| <code>AbstractJsfTestCase</code> that also provides convenient |
| utility methods needed to test common scenarios in unit tests for |
| <code>ViewController</code> implementation classes.</li> |
| </ul> |
| |
| <p>If you use one of these base classes, the <code>setUp()</code> method |
| found there will initialize a set of <code>protected</code> instance |
| variables for the container-managed objects you might need to access. |
| The set of initialized variables includes (variable name and type):</p> |
| <ul> |
| <li><code>application</code> (<code>MockApplication</code>)</li> |
| <li><code>config</code> (<code>MockServletConfig</code>)</li> |
| <li><code>externalContext</code> (<code>MockExternalContext</code>)</li> |
| <li><code>facesContext</code> (<code>MockFacesContext</code>)</li> |
| <li><code>lifecycle</code> (<code>MockLifecycle</code>)</li> |
| <li><code>request</code> (<code>MockHttpServletRequest</code>)</li> |
| <li><code>response</code> (<code>MockHttpServletResonse</code>)</li> |
| <li><code>servletContext</code> (<code>MockServletContext</code>)</li> |
| <li><code>session</code> (<code>MockHttpSession</code>)</li> |
| </ul> |
| |
| </subsection> |
| |
| <a name="test-using"/> |
| <subsection name="Using The Test Framework"> |
| |
| <p>The most common scenario for using the Test Framework is to construct |
| test cases for <code>ViewController</code> implementation classes. |
| Because the runtime environment of a <code>ViewController</code> is |
| quite constrained, it is easy to construct isolated unit tests that |
| exercise the methods exposed by a <code>ViewController</code> class. |
| The <em>Shale Use Cases</em> web application (included in the distribution) |
| contains many examples of such test cases, in the <code>src/test</code> |
| directory. We will use <code>org.apache.shale.usecases.locale.SelectTestCase</code> |
| (which tests the <code>org.apache.shale.usecases.locale.Select</code> |
| implementation) as an example of how such a test case can be constructed.</p> |
| |
| <ol> |
| <li>Create a new Java class <code>SelectTestCase</code>, in a package |
| directory (typically under <code>src/test</code> in your project) |
| that is the same as the package directory for the class you will be |
| testing. This allows your test case to access package private and |
| protected variables and methods in the class being tested.</li> |
| <li>Make sure that the package declaration matches that of the class to |
| be tested (in this case, <code>org.apache.shale.usecases.locale</code>.</li> |
| <li>Declare your class to extend <code>AbstractViewControllerTestCase</code> |
| (or, if you are not testing a <code>ViewController</code> implementation, |
| extend <code>AbstractJsfTestCase</code>): |
| <source> |
| public class SelectTestCase extends AbstractViewControllerTestCase { |
| ... |
| } |
| </source></li> |
| <li>Create a constructor that takes a <code>String</code> parameter, and |
| passes it to the superclass constructor: |
| <source> |
| public SelectTestCase(String name) { |
| super(name); |
| } |
| </source></li> |
| <li>Create a <code>setUp()</code> method and <strong>be sure</strong> |
| to call <code>super.setUp()</code> at the beginning. This method |
| will be called by JUnit immediately before it executes each |
| test method. |
| <source> |
| public void setUp() { |
| super.setUp(); |
| // Customization will go here |
| } |
| </source></li> |
| <li>After the call to the superclass <code>setUp()</code> method, |
| perform any other initialization required to execute the tests |
| in this test case. In our example case, a configuration method |
| on the <code>MockApplication</code> instance will be used to |
| define the default and supported <code>Locale</code>s for this |
| set of tests. This corresponds to what would happen at runtime, |
| when the JavaServer Faces initialization process used the contents |
| of the <code>/WEB-INF/faces-config.xml</code> resource to initialize |
| these values. In addition, we will create a new instance of the |
| <code>Select</code> class to be tested. It is important to create |
| a new instance for each test, to ensure that execution of one test |
| does not get influenced by the leftover property settings from a |
| previous test. |
| <source> |
| public void setUp() { |
| super.setUp(); |
| |
| // Configure the supported locales for this application |
| List list = new ArrayList(); |
| list.add(new Locale("en")); |
| list.add(new Locale("fr")); |
| list.add(new Locale("de")); |
| list.add(new Locale("es")); |
| application.setSupportedLocales(list); |
| |
| // Construct a new ViewController instance |
| vc = new Select(); |
| |
| } |
| </source></li> |
| <li>Create a <code>tearDown()</code> method that cleans up any custom |
| variables you allocated in your <code>setUp()</code> method, and |
| then calls the <code>super.tearDown()</code> method. This will be |
| called by JUnit after each test is executed. |
| <source> |
| public void tearDown() { |
| vc = null; |
| super.tearDown(); |
| } |
| </source></li> |
| <li>Declare the custom instance variable(s) that you are setting up |
| in your <code>setUp()</code> method. In this case, we create an |
| instance of the <code>ViewController</code> class to be tested. |
| A new instance will be created (via a call from JUnit to the |
| <code>setUp()</code> method) before each test method is executed. |
| <source> |
| // The instance to be tested |
| Select vc = null; |
| </source></li> |
| <li>Create one or more individual test methods (which must be |
| <code>public</code>, return <code>void</code>, take no arguments, |
| and have a method name of the form <code>testXXXX</code>. For |
| advice on how to construct such methods, consult the |
| <a href="http://junit.org/">JUnit Web Site</a>, or any of the |
| large number of resources on the web describing how to use JUnit |
| to build unit tests. The following example tests what happens |
| when the <code>select()</code> method (which is executed when |
| the <em>Go</em> button is pressed), but the value entered is not |
| one of the valid options. <strong>NOTE</strong> that the test |
| method must emulate the runtime calls to the <code>ViewController</code> |
| event methods, because there is no actual runtime container |
| available to perform these tasks automatically: |
| <source> |
| // Test behavior of select() with an invalid value |
| public void testSelectInvalid() { |
| |
| Locale locale = new Locale("en"); |
| facesContext.getViewRoot().setLocale(locale); |
| vc.init(); |
| vc.preprocess(); |
| vc.setLocale("it"); |
| String result = vc.select(); |
| assertEquals(Select.FAILURE, result); |
| checkMessageCount(1); |
| assertEquals(locale, facesContext.getViewRoot().getLocale()); |
| |
| } |
| </source> |
| The test case sets the <code>locale</code> property (which is |
| bound to a dropdown component at runtime, but we are simulating |
| the behavior of Update Model Values here) to an invalid value, |
| then calls the <code>select()</code> method. The test then |
| verifies that the logical outcome returned matches that which |
| is expected (<code>Select.FAILURE</code>), that there was an error |
| message queued to be displayed, and that the <code>locale</code> |
| for the current view was <strong>NOT</strong> actually changed. |
| <br/></li> |
| <li>Finally, integrate the execution of this test case into your |
| build script. Many IDEs will take care of this for you; however, |
| if you are creating an Ant build script by hand, you might find |
| the <code>test</code> target from the Shale Use Cases example |
| a useful starting point. It locates <em>all</em> the test cases |
| related to the entire application, and executes them: |
| <source> |
| <target name="test" depends="test.compile" |
| description="Execute unit tests"> |
| |
| <mkdir dir="${build.home}/test-results"/> |
| |
| <echo message="Running unit tests ..."/> |
| <junit printSummary="no" fork="yes" |
| haltonfailure="yes" haltonerror="yes"> |
| <classpath refid="test.classpath"/> |
| <formatter type="plain" |
| usefile="false"/> |
| <formatter type="xml" |
| usefile="true"/> |
| <batchtest todir="${build.home}/test-results"> |
| <fileset dir="${build.home}/test-classes" |
| includes="org/apache/shale/usecases/*/*TestCase.class"/> |
| </batchtest> |
| </junit> |
| |
| </target> |
| </source></li> |
| </ol> |
| |
| </subsection> |
| |
| </section> |
| |
| </body> |
| |
| </document> |