You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ta...@apache.org on 2018/10/21 08:14:24 UTC

[myfaces] branch master updated: Merged myfaces-test30 in core

This is an automated email from the ASF dual-hosted git repository.

tandraschko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/myfaces.git


The following commit(s) were added to refs/heads/master by this push:
     new 0126d50  Merged myfaces-test30 in core
0126d50 is described below

commit 0126d50452e2b1a884fa490c7ff98d2dd7dcb501
Author: Thomas Andraschko <ta...@apache.org>
AuthorDate: Sun Oct 21 10:14:09 2018 +0200

    Merged myfaces-test30 in core
---
 impl/pom.xml                                       |    6 +-
 parent/pom.xml                                     |    7 -
 pom.xml                                            |    1 +
 test/pom.xml                                       |  189 ++++
 .../myfaces/test/base/AbstractJsfTestCase.java     |  357 ++++++
 .../test/base/AbstractViewControllerTestCase.java  |  101 ++
 .../AbstractJsfConfigurableMockTestCase.java       |  359 ++++++
 ...actJsfConfigurableMultipleRequestsTestCase.java |  399 +++++++
 .../test/base/junit4/AbstractJsfTestCase.java      |  360 ++++++
 .../junit4/AbstractViewControllerTestCase.java     |  103 ++
 .../apache/myfaces/test/cargo/CargoTestSetup.java  |  179 +++
 .../apache/myfaces/test/config/ConfigParser.java   |  709 ++++++++++++
 .../test/config/ResourceBundleVarNames.java        |   50 +
 .../apache/myfaces/test/el/AbstractELResolver.java |   78 ++
 .../myfaces/test/el/ExpressionTokenizer.java       |  193 ++++
 .../test/el/FacesImplicitObjectELResolver.java     |  317 ++++++
 .../test/el/FacesResourceBundleELResolver.java     |  236 ++++
 .../test/el/FacesScopedAttributeELResolver.java    |  269 +++++
 .../test/el/FacesVariableResolverChainWrapper.java |  143 +++
 .../test/el/MockCompositeValueExpression.java      |  180 +++
 .../org/apache/myfaces/test/el/MockELContext.java  |  122 ++
 .../myfaces/test/el/MockExpressionFactory.java     |  365 ++++++
 .../apache/myfaces/test/el/MockFunctionMapper.java |   74 ++
 .../myfaces/test/el/MockMethodExpression.java      |  267 +++++
 .../myfaces/test/el/MockValueExpression.java       |  307 +++++
 .../apache/myfaces/test/el/MockVariableMapper.java |   80 ++
 .../test/el/MockVariableValueExpression.java       |  215 ++++
 .../myfaces/test/el/ReservedWordsELResolver.java   |  122 ++
 .../test/htmlunit/AbstractHtmlUnitTestCase.java    |  333 ++++++
 .../htmlunit/junit4/AbstractHtmlUnitTestCase.java  |  322 ++++++
 .../test/jmock/AbstractJmockJsfTestCase.java       |  354 ++++++
 .../myfaces/test/mock/MockActionListener.java      |   65 ++
 .../apache/myfaces/test/mock/MockApplication.java  |  407 +++++++
 .../myfaces/test/mock/MockApplication12.java       |  307 +++++
 .../myfaces/test/mock/MockApplication20.java       | 1188 ++++++++++++++++++++
 .../myfaces/test/mock/MockApplication22.java       |   62 +
 .../myfaces/test/mock/MockApplication30.java       |   62 +
 .../myfaces/test/mock/MockApplicationFactory.java  |  149 +++
 .../apache/myfaces/test/mock/MockClientWindow.java |  104 ++
 .../myfaces/test/mock/MockClientWindowFactory.java |   91 ++
 .../apache/myfaces/test/mock/MockEnumeration.java  |   77 ++
 .../myfaces/test/mock/MockExceptionHandler.java    |  220 ++++
 .../test/mock/MockExceptionHandlerFactory.java     |   40 +
 .../myfaces/test/mock/MockExternalContext.java     |  540 +++++++++
 .../myfaces/test/mock/MockExternalContext12.java   |  117 ++
 .../myfaces/test/mock/MockExternalContext20.java   |  358 ++++++
 .../myfaces/test/mock/MockExternalContext22.java   |  109 ++
 .../apache/myfaces/test/mock/MockFacesContext.java |  330 ++++++
 .../myfaces/test/mock/MockFacesContext12.java      |  116 ++
 .../myfaces/test/mock/MockFacesContext20.java      |  183 +++
 .../myfaces/test/mock/MockFacesContext22.java      |  121 ++
 .../myfaces/test/mock/MockFacesContextFactory.java |  315 ++++++
 .../org/apache/myfaces/test/mock/MockFlash.java    |  823 ++++++++++++++
 .../apache/myfaces/test/mock/MockFlowHandler.java  |   90 ++
 .../myfaces/test/mock/MockHttpServletRequest.java  | 1094 ++++++++++++++++++
 .../myfaces/test/mock/MockHttpServletResponse.java |  474 ++++++++
 .../apache/myfaces/test/mock/MockHttpSession.java  |  454 ++++++++
 .../myfaces/test/mock/MockHttpSessionProxy.java    |  205 ++++
 .../myfaces/test/mock/MockNavigationHandler.java   |  110 ++
 .../myfaces/test/mock/MockPartialViewContext.java  |  375 ++++++
 .../test/mock/MockPartialViewContextFactory.java   |   41 +
 .../myfaces/test/mock/MockPortletContext.java      |  358 ++++++
 .../myfaces/test/mock/MockPortletRequest.java      |  436 +++++++
 .../myfaces/test/mock/MockPortletResponse.java     |   67 ++
 .../myfaces/test/mock/MockPortletSession.java      |  291 +++++
 .../apache/myfaces/test/mock/MockPrincipal.java    |   79 ++
 .../apache/myfaces/test/mock/MockPrintWriter.java  |   84 ++
 .../apache/myfaces/test/mock/MockRenderKit.java    |  145 +++
 .../myfaces/test/mock/MockRenderKitFactory.java    |  117 ++
 .../myfaces/test/mock/MockRequestDispatcher.java   |   60 +
 .../test/mock/MockResponseStateManager.java        |  396 +++++++
 .../myfaces/test/mock/MockResponseWriter.java      |  428 +++++++
 .../org/apache/myfaces/test/mock/MockServlet.java  |  119 ++
 .../myfaces/test/mock/MockServletConfig.java       |  124 ++
 .../myfaces/test/mock/MockServletContext.java      |  746 ++++++++++++
 .../myfaces/test/mock/MockServletInputStream.java  |   54 +
 .../myfaces/test/mock/MockServletOutputStream.java |   93 ++
 .../myfaces/test/mock/MockServletRegistration.java |  103 ++
 .../apache/myfaces/test/mock/MockStateManager.java |  112 ++
 .../apache/myfaces/test/mock/MockSubKeyMap.java    |  315 ++++++
 .../apache/myfaces/test/mock/MockViewHandler.java  |  169 +++
 .../myfaces/test/mock/MockViewHandler20.java       |   52 +
 .../apache/myfaces/test/mock/MockWebContainer.java |  299 +++++
 .../myfaces/test/mock/MockedJsfTestContainer.java  |  415 +++++++
 .../myfaces/test/mock/_AbstractAttributeMap.java   |  448 ++++++++
 .../apache/myfaces/test/mock/_ApplicationMap.java  |   78 ++
 .../org/apache/myfaces/test/mock/_CookieMap.java   |  167 +++
 .../java/org/apache/myfaces/test/mock/_ELText.java |  444 ++++++++
 .../java/org/apache/myfaces/test/mock/_Hex.java    |  341 ++++++
 .../myfaces/test/mock/_InitParameterMap.java       |   80 ++
 .../apache/myfaces/test/mock/_NullEnumeration.java |   49 +
 .../myfaces/test/mock/_RequestHeaderMap.java       |   80 ++
 .../myfaces/test/mock/_RequestHeaderValuesMap.java |   93 ++
 .../org/apache/myfaces/test/mock/_RequestMap.java  |   78 ++
 .../myfaces/test/mock/_RequestParameterMap.java    |   67 ++
 .../test/mock/_RequestParameterValuesMap.java      |   67 ++
 .../org/apache/myfaces/test/mock/_SessionMap.java  |   88 ++
 .../mock/lifecycle/ApplyRequestValuesExecutor.java |   45 +
 .../mock/lifecycle/DefaultRestoreViewSupport.java  |  124 ++
 .../mock/lifecycle/InvokeApplicationExecutor.java  |   45 +
 .../myfaces/test/mock/lifecycle/MockLifecycle.java |  201 ++++
 .../test/mock/lifecycle/MockLifecycleFactory.java  |   87 ++
 .../myfaces/test/mock/lifecycle/PhaseExecutor.java |   49 +
 .../test/mock/lifecycle/PhaseListenerManager.java  |  126 +++
 .../mock/lifecycle/ProcessValidationsExecutor.java |   43 +
 .../mock/lifecycle/RenderResponseExecutor.java     |   60 +
 .../test/mock/lifecycle/RestoreViewExecutor.java   |  199 ++++
 .../test/mock/lifecycle/RestoreViewSupport.java    |   74 ++
 .../mock/lifecycle/UpdateModelValuesExecutor.java  |   45 +
 .../resource/MockClassLoaderResourceLoader.java    |  130 +++
 .../MockExternalContextResourceLoader.java         |  223 ++++
 .../myfaces/test/mock/resource/MockResource.java   |  105 ++
 .../test/mock/resource/MockResourceHandler.java    |  401 +++++++
 .../mock/resource/MockResourceHandlerSupport.java  |  124 ++
 .../test/mock/resource/MockResourceLoader.java     |  158 +++
 .../test/mock/resource/MockResourceMeta.java       |  123 ++
 .../test/mock/resource/MockSimpleResource.java     |  200 ++++
 .../mock/resource/MockSimpleResourceHandler.java   |  410 +++++++
 .../myfaces/test/mock/visit/FullVisitContext.java  |  148 +++
 .../myfaces/test/mock/visit/MockVisitCallback.java |   41 +
 .../myfaces/test/mock/visit/MockVisitContext.java  |  106 ++
 .../test/mock/visit/MockVisitContextFactory.java   |   53 +
 .../test/mock/visit/PartialVisitContext.java       |  469 ++++++++
 .../apache/myfaces/test/runners/NamedRunner.java   |  126 +++
 .../myfaces/test/runners/TestClassLoader.java      |  359 ++++++
 .../test/runners/TestPerClassLoaderRunner.java     |  299 +++++
 .../org/apache/myfaces/test/util/Jsf11Utils.java   |   30 +
 .../org/apache/myfaces/test/util/Jsf12Utils.java   |   39 +
 .../org/apache/myfaces/test/util/JsfVersion.java   |   78 ++
 129 files changed, 27277 insertions(+), 9 deletions(-)

diff --git a/impl/pom.xml b/impl/pom.xml
index 5bef8ce..46c0554 100644
--- a/impl/pom.xml
+++ b/impl/pom.xml
@@ -1187,8 +1187,10 @@
         </dependency>
 
         <dependency>
-            <groupId>org.apache.myfaces.test</groupId>
-            <artifactId>myfaces-test30</artifactId>
+            <groupId>org.apache.myfaces.core</groupId>
+            <artifactId>myfaces-test</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
         </dependency>
 
         <!-- easymock -->
diff --git a/parent/pom.xml b/parent/pom.xml
index 8038a17..4964872 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -557,13 +557,6 @@
                 <scope>test</scope>
             </dependency>
 
-            <dependency>
-                <groupId>org.apache.myfaces.test</groupId>
-                <artifactId>myfaces-test30</artifactId>
-                <version>1.0.9-SNAPSHOT</version>
-                <scope>test</scope>
-            </dependency>
-
             <!-- easymock -->
             <dependency>
                 <groupId>org.easymock</groupId>
diff --git a/pom.xml b/pom.xml
index 5903851..733777b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,6 +52,7 @@
     <modules>
         <module>parent</module>
         <module>api</module>
+        <module>test</module>
         <module>impl</module>
         <module>bundle</module>
     </modules>
diff --git a/test/pom.xml b/test/pom.xml
new file mode 100644
index 0000000..5a6d6ba
--- /dev/null
+++ b/test/pom.xml
@@ -0,0 +1,189 @@
+<!--
+/*
+ * 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.
+ *
+ * $Id: pom.xml 1326869 2012-04-17 01:30:30Z lu4242 $
+ */
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.myfaces.core</groupId>
+        <artifactId>myfaces-core-project</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+        <relativePath>../parent/pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.apache.myfaces.core</groupId>
+    <artifactId>myfaces-test</artifactId>
+    <packaging>jar</packaging>
+    <name>Apache MyFaces Core 3.0 - Test</name>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>net.sourceforge.htmlunit</groupId>
+            <artifactId>htmlunit</artifactId>
+            <version>1.14</version>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-digester</groupId>
+            <artifactId>commons-digester</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>jmock</groupId>
+            <artifactId>jmock</artifactId>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>jmock</groupId>
+            <artifactId>jmock-cglib</artifactId>
+            <scope>compile</scope>
+        </dependency>
+
+        <!-- For the "org.apache.shale.test.cargo" package, we need to have  -->
+        <!-- JUnit as a compile time dependency, not just scope="test".      -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.5</version>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.codehaus.cargo</groupId>
+            <artifactId>cargo-core-uberjar</artifactId>
+            <version>0.8</version>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.codehaus.cargo</groupId>
+            <artifactId>cargo-ant</artifactId>
+            <version>0.8</version>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.portlet</groupId>
+            <artifactId>portlet-api</artifactId>
+            <version>1.0</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.myfaces.core</groupId>
+            <artifactId>myfaces-api</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <!--
+        <dependency>
+            <groupId>javax.faces</groupId>
+            <artifactId>javax.faces-api</artifactId>
+            <version>2.2</version>
+            <scope>provided</scope>
+        </dependency>-->
+
+        <!-- Servlet 3.0 -->
+        <dependency>
+             <groupId>org.apache.geronimo.specs</groupId>
+             <artifactId>geronimo-servlet_3.0_spec</artifactId>
+             <version>1.0</version>
+             <scope>provided</scope>
+        </dependency>
+        <!-- JSP 2.1 -->
+        <dependency>
+             <groupId>org.apache.geronimo.specs</groupId>
+             <artifactId>geronimo-jsp_2.1_spec</artifactId>
+             <version>1.0.1</version>
+             <scope>provided</scope>
+        </dependency>
+        <!-- EL 1.0 -->
+        <dependency>
+             <groupId>org.apache.geronimo.specs</groupId>
+             <artifactId>geronimo-el_1.0_spec</artifactId>
+             <version>1.0.2</version>
+             <scope>provided</scope>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-source-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-source</id>
+                        <goals>
+                            <goal>jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+    <profiles>
+        <profile>
+            <id>generate-assembly</id>
+            <activation>
+                <property>
+                    <name>performRelease</name>
+                    <value>true</value>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-javadoc-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-javadoc</id>
+                                <goals>
+                                    <goal>jar</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+    <reporting>
+      <plugins>
+        <plugin>
+          <artifactId>maven-javadoc-plugin</artifactId>
+          <reportSets>
+            <reportSet>
+              <id>non-aggregate</id>
+              <configuration>
+              </configuration>
+              <reports>
+                <report>javadoc</report>
+              </reports>
+            </reportSet>
+          </reportSets>
+        </plugin>
+      </plugins>
+    </reporting>
+</project>
diff --git a/test/src/main/java/org/apache/myfaces/test/base/AbstractJsfTestCase.java b/test/src/main/java/org/apache/myfaces/test/base/AbstractJsfTestCase.java
new file mode 100644
index 0000000..4f76c28
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/base/AbstractJsfTestCase.java
@@ -0,0 +1,357 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.base;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import javax.faces.FactoryFinder;
+import javax.faces.application.ApplicationFactory;
+import javax.faces.component.UIViewRoot;
+import javax.faces.lifecycle.LifecycleFactory;
+import javax.faces.render.RenderKitFactory;
+
+import junit.framework.TestCase;
+
+import org.apache.myfaces.test.config.ResourceBundleVarNames;
+import org.apache.myfaces.test.mock.MockApplication;
+import org.apache.myfaces.test.mock.MockExternalContext;
+import org.apache.myfaces.test.mock.MockFacesContext;
+import org.apache.myfaces.test.mock.MockFacesContextFactory;
+import org.apache.myfaces.test.mock.MockHttpServletRequest;
+import org.apache.myfaces.test.mock.MockHttpServletResponse;
+import org.apache.myfaces.test.mock.MockHttpSession;
+import org.apache.myfaces.test.mock.MockRenderKit;
+import org.apache.myfaces.test.mock.MockServletConfig;
+import org.apache.myfaces.test.mock.MockServletContext;
+import org.apache.myfaces.test.mock.lifecycle.MockLifecycle;
+import org.apache.myfaces.test.mock.lifecycle.MockLifecycleFactory;
+
+/**
+ * <p>Abstract JUnit test case base class, which sets up the JavaServer Faces
+ * mock object environment for a particular simulated request.  The following
+ * protected variables are initialized in the <code>setUp()</code> method, and
+ * cleaned up in the <code>tearDown()</code> method:</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>MockHttpServletResponse</code>)</li>
+ * <li><code>servletContext</code> (<code>MockServletContext</code>)</li>
+ * <li><code>session</code> (<code>MockHttpSession</code>)</li>
+ * </ul>
+ *
+ * <p>In addition, appropriate factory classes will have been registered with
+ * <code>javax.faces.FactoryFinder</code> for <code>Application</code> and
+ * <code>RenderKit</code> instances.  The created <code>FacesContext</code>
+ * instance will also have been registered in the proper thread local
+ * variable, to simulate what a servlet container would do.</p>
+ *
+ * <p><strong>WARNING</strong> - If you choose to subclass this class, be sure
+ * your <code>setUp()</code> and <code>tearDown()</code> methods call
+ * <code>super.setUp()</code> and <code>super.tearDown()</code> respectively,
+ * and that you implement your own <code>suite()</code> method that exposes
+ * the test methods for your test case.</p>
+ * 
+ * @since 1.0.0
+ */
+
+public abstract class AbstractJsfTestCase extends TestCase
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct a new instance of this test case.</p>
+     *
+     * @param name Name of this test case
+     */
+    public AbstractJsfTestCase(String name)
+    {
+        super(name);
+    }
+
+    // ---------------------------------------------------- Overall Test Methods
+
+    /**
+     * <p>Set up instance variables required by this test case.</p>
+     */
+    protected void setUp() throws Exception
+    {
+        // Set up a new thread context class loader
+        setUpClassloader();
+
+        // Set up Servlet API Objects
+        setUpServletObjects();
+
+        // Set up JSF API Objects
+        FactoryFinder.releaseFactories();
+
+        setFactories();
+
+        setUpJSFObjects();
+    }
+    
+    /**
+     * Set up the thread context classloader. JSF uses the this classloader
+     * in order to find related factory classes and other resources, but in
+     * some selected cases, the default classloader cannot be properly set.
+     * 
+     * @throws Exception 
+     */
+    protected void setUpClassloader() throws Exception
+    {
+        threadContextClassLoader = Thread.currentThread()
+                .getContextClassLoader();
+        Thread.currentThread()
+                .setContextClassLoader(
+                        new URLClassLoader(new URL[0], this.getClass()
+                                .getClassLoader()));
+        classLoaderSet = true;
+    }
+
+    /**
+     * <p>Setup JSF object used for the test. By default it calls to the following
+     * methods in this order:</p>
+     * 
+     * <ul>
+     * <li><code>setUpExternalContext();</code></li>
+     * <li><code>setUpLifecycle();</code></li>
+     * <li><code>setUpFacesContext();</code></li>
+     * <li><code>setUpView();</code></li>
+     * <li><code>setUpApplication();</code></li>
+     * <li><code>setUpRenderKit();</code></li>
+     * </ul>
+     * 
+     * @throws Exception
+     */
+    protected void setUpJSFObjects() throws Exception
+    {
+        setUpExternalContext();
+        setUpLifecycle();
+        setUpFacesContext();
+        setUpView();
+        setUpApplication();
+        setUpRenderKit();
+    }
+
+    /**
+     * <p>Setup servlet objects that will be used for the test:</p>
+     * 
+     * <ul>
+     * <li><code>config</code> (<code>MockServletConfig</code>)</li>
+     * <li><code>servletContext</code> (<code>MockServletContext</code>)</li>
+     * <li><code>request</code> (<code>MockHttpServletRequest</code></li>
+     * <li><code>response</code> (<code>MockHttpServletResponse</code>)</li>
+     * <li><code>session</code> (<code>MockHttpSession</code>)</li>
+     * </ul>
+     * 
+     * @throws Exception
+     */
+    protected void setUpServletObjects() throws Exception
+    {
+        servletContext = new MockServletContext();
+        config = new MockServletConfig(servletContext);
+        session = new MockHttpSession();
+        session.setServletContext(servletContext);
+        request = new MockHttpServletRequest(session);
+        request.setServletContext(servletContext);
+        response = new MockHttpServletResponse();
+    }
+
+    /**
+     * <p>Set JSF factories using FactoryFinder method setFactory.</p>
+     * 
+     * @throws Exception
+     */
+    protected void setFactories() throws Exception
+    {
+        FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY,
+                "org.apache.myfaces.test.mock.MockApplicationFactory");
+        FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY,
+                "org.apache.myfaces.test.mock.MockFacesContextFactory");
+        FactoryFinder.setFactory(FactoryFinder.LIFECYCLE_FACTORY,
+                "org.apache.myfaces.test.mock.lifecycle.MockLifecycleFactory");
+        FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY,
+                "org.apache.myfaces.test.mock.MockRenderKitFactory");
+        FactoryFinder.setFactory(FactoryFinder.EXCEPTION_HANDLER_FACTORY,
+                "org.apache.myfaces.test.mock.MockExceptionHandlerFactory");
+        FactoryFinder.setFactory(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY,
+                "org.apache.myfaces.test.mock.MockPartialViewContextFactory");
+        FactoryFinder.setFactory(FactoryFinder.VISIT_CONTEXT_FACTORY,
+                "org.apache.myfaces.test.mock.visit.MockVisitContextFactory");
+        FactoryFinder.setFactory(FactoryFinder.CLIENT_WINDOW_FACTORY,
+                "org.apache.myfaces.test.mock.MockClientWindowFactory");
+    }
+
+    /**
+     * Setup the <code>externalContext</code> variable, using the 
+     * servlet variables already initialized.
+     * 
+     * @throws Exception
+     */
+    protected void setUpExternalContext() throws Exception
+    {
+        externalContext = new MockExternalContext(servletContext, request,
+                response);
+    }
+
+    /**
+     * Setup the <code>lifecycle</code> and <code>lifecycleFactory</code>
+     * variables.
+     * 
+     * @throws Exception
+     */
+    protected void setUpLifecycle() throws Exception
+    {
+        lifecycleFactory = (MockLifecycleFactory) FactoryFinder
+                .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
+        lifecycle = (MockLifecycle) lifecycleFactory
+                .getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
+    }
+
+    /**
+     * Setup the <code>facesContextFactory</code> and <code>facesContext</code>
+     * variable. Before end, by default it override <code>externalContext</code>
+     * variable from the value retrieved from facesContext.getExternalContext(),
+     * because sometimes it is possible facesContext overrides externalContext
+     * internally.
+     * 
+     * @throws Exception
+     */
+    protected void setUpFacesContext() throws Exception
+    {
+        facesContextFactory = (MockFacesContextFactory) FactoryFinder
+                .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
+        facesContext = (MockFacesContext) facesContextFactory.getFacesContext(
+                servletContext, request, response, lifecycle);
+        if (facesContext.getExternalContext() != null)
+        {
+            externalContext = (MockExternalContext) facesContext
+                    .getExternalContext();
+        }
+    }
+
+    /**
+     * By default, create an instance of UIViewRoot, set its viewId as "/viewId"
+     * and assign it to the current facesContext.
+     * 
+     * @throws Exception
+     */
+    protected void setUpView() throws Exception
+    {
+        UIViewRoot root = new UIViewRoot();
+        root.setViewId("/viewId");
+        root.setRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT);
+        facesContext.setViewRoot(root);
+    }
+
+    /**
+     * Setup the <code>application</code> variable and before
+     * the end by default it is assigned to the <code>facesContext</code>
+     * variable, calling <code>facesContext.setApplication(application)</code>
+     * 
+     * @throws Exception
+     */
+    protected void setUpApplication() throws Exception
+    {
+        ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder
+                .getFactory(FactoryFinder.APPLICATION_FACTORY);
+        application = (MockApplication) applicationFactory.getApplication();
+        facesContext.setApplication(application);
+    }
+
+    /**
+     * Setup the <code>renderKit</code> variable. This is a good place to use
+     * <code>ConfigParser</code> to register converters, validators, components
+     * or renderkits.
+     * 
+     * @throws Exception
+     */
+    protected void setUpRenderKit() throws Exception
+    {
+        RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder
+                .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+        renderKit = new MockRenderKit();
+        renderKitFactory.addRenderKit(RenderKitFactory.HTML_BASIC_RENDER_KIT,
+                renderKit);
+    }
+
+    /**
+     * <p>Tear down instance variables required by this test case.</p>
+     */
+    protected void tearDown() throws Exception
+    {
+
+        application = null;
+        config = null;
+        externalContext = null;
+        if (facesContext != null)
+        {
+            facesContext.release();
+        }
+        facesContext = null;
+        lifecycle = null;
+        lifecycleFactory = null;
+        renderKit = null;
+        request = null;
+        response = null;
+        servletContext = null;
+        session = null;
+        FactoryFinder.releaseFactories();
+        ResourceBundleVarNames.resetNames();
+
+        tearDownClassloader();
+    }
+    
+    protected void tearDownClassloader() throws Exception
+    {
+        if (classLoaderSet)
+        {
+            Thread.currentThread().setContextClassLoader(threadContextClassLoader);
+            threadContextClassLoader = null;
+            classLoaderSet = false;
+        }
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    // Mock object instances for our tests
+    protected MockApplication application = null;
+    protected MockServletConfig config = null;
+    protected MockExternalContext externalContext = null;
+    protected MockFacesContext facesContext = null;
+    protected MockFacesContextFactory facesContextFactory = null;
+    protected MockLifecycle lifecycle = null;
+    protected MockLifecycleFactory lifecycleFactory = null;
+    protected MockRenderKit renderKit = null;
+    protected MockHttpServletRequest request = null;
+    protected MockHttpServletResponse response = null;
+    protected MockServletContext servletContext = null;
+    protected MockHttpSession session = null;
+
+    // Thread context class loader saved and restored after each test
+    private ClassLoader threadContextClassLoader = null;
+    private boolean classLoaderSet = false;
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/base/AbstractViewControllerTestCase.java b/test/src/main/java/org/apache/myfaces/test/base/AbstractViewControllerTestCase.java
new file mode 100644
index 0000000..aefc876
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/base/AbstractViewControllerTestCase.java
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.base;
+
+import java.util.Iterator;
+
+/**
+ * <p>Abstract base class for testing <code>ViewController</code>
+ * implementations.</p>
+ *
+ * <p><strong>WARNING</strong> - If you choose to subclass this class, be sure
+ * your <code>setUp()</code> and <code>tearDown()</code> methods call
+ * <code>super.setUp()</code> and <code>super.tearDown()</code> respectively,
+ * and that you implement your own <code>suite()</code> method that exposes
+ * the test methods for your test case.</p>
+ * 
+ * @since 1.0.0
+ */
+public abstract class AbstractViewControllerTestCase extends
+        AbstractJsfTestCase
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct a new instance of this test case.</p>
+     *
+     * @param name Test case name
+     */
+    public AbstractViewControllerTestCase(String name)
+    {
+        super(name);
+    }
+
+    // ---------------------------------------------------- Overall Test Methods
+
+    // ------------------------------------------------------ Instance Variables
+
+    // ------------------------------------------------------- Protected Methods
+
+    /**
+     * <p>Test that the specified number of messages have been queued on the
+     * <code>FacesContext</code> instance, without regard to matching a
+     * particular client identifier.</p>
+     *
+     * @param expected The expected number of messages
+     */
+    protected void checkMessageCount(int expected)
+    {
+
+        int actual = 0;
+        Iterator messages = facesContext.getMessages();
+        while (messages.hasNext())
+        {
+            messages.next();
+            actual++;
+        }
+        assertEquals("Complete message count", expected, actual);
+
+    }
+
+    /**
+     * <p>Test that the specified number of messages have been queued on the
+     * <code>FacesContext</code> instance, for the specified client id.</p>
+     *
+     * @param clientId Client identifier of the component for which to
+     *  count queued messages
+     * @param expected The expected number of messages
+     */
+    protected void checkMessageCount(String clientId, int expected)
+    {
+
+        int actual = 0;
+        Iterator messages = facesContext.getMessages(clientId);
+        while (messages.hasNext())
+        {
+            messages.next();
+            actual++;
+        }
+        assertEquals("Complete message count", expected, actual);
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/base/junit4/AbstractJsfConfigurableMockTestCase.java b/test/src/main/java/org/apache/myfaces/test/base/junit4/AbstractJsfConfigurableMockTestCase.java
new file mode 100644
index 0000000..7f65067
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/base/junit4/AbstractJsfConfigurableMockTestCase.java
@@ -0,0 +1,359 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.base.junit4;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import javax.faces.FactoryFinder;
+import javax.faces.application.Application;
+import javax.faces.application.ApplicationFactory;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.context.FacesContextFactory;
+import javax.faces.lifecycle.Lifecycle;
+import javax.faces.lifecycle.LifecycleFactory;
+import javax.faces.render.RenderKit;
+import javax.faces.render.RenderKitFactory;
+
+import org.apache.myfaces.test.config.ResourceBundleVarNames;
+import org.apache.myfaces.test.mock.MockExternalContext;
+import org.apache.myfaces.test.mock.MockFacesContext;
+import org.apache.myfaces.test.mock.MockHttpServletRequest;
+import org.apache.myfaces.test.mock.MockHttpServletResponse;
+import org.apache.myfaces.test.mock.MockHttpSession;
+import org.apache.myfaces.test.mock.MockRenderKit;
+import org.apache.myfaces.test.mock.MockServletConfig;
+import org.apache.myfaces.test.mock.MockServletContext;
+import org.junit.After;
+import org.junit.Before;
+
+/**
+ * <p>Abstract JUnit 4.5 test case base class, which sets up the JavaServer Faces
+ * mock object environment for a particular simulated request.  The following
+ * protected variables are initialized in the <code>setUp()</code> method, and
+ * cleaned up in the <code>tearDown()</code> method:</p>
+ * <ul>
+ * <li><code>application</code> (<code>Application</code>)</li>
+ * <li><code>config</code> (<code>MockServletConfig</code>)</li>
+ * <li><code>externalContext</code> (<code>ExternalContext</code>)</li>
+ * <li><code>facesContext</code> (<code>FacesContext</code>)</li>
+ * <li><code>lifecycle</code> (<code>Lifecycle</code>)</li>
+ * <li><code>request</code> (<code>MockHttpServletRequest</code></li>
+ * <li><code>response</code> (<code>MockHttpServletResponse</code>)</li>
+ * <li><code>servletContext</code> (<code>MockServletContext</code>)</li>
+ * <li><code>session</code> (<code>MockHttpSession</code>)</li>
+ * </ul>
+ *
+ * <p>In addition, appropriate factory classes will have been registered with
+ * <code>javax.faces.FactoryFinder</code> for <code>Application</code> and
+ * <code>RenderKit</code> instances.  The created <code>FacesContext</code>
+ * instance will also have been registered in the proper thread local
+ * variable, to simulate what a servlet container would do.</p>
+ *
+ * <p><strong>WARNING</strong> - If you choose to subclass this class, be sure
+ * your <code>setUp()</code> and <code>tearDown()</code> methods call
+ * <code>super.setUp()</code> and <code>super.tearDown()</code> respectively,
+ * and that you implement your own <code>suite()</code> method that exposes
+ * the test methods for your test case.</p>
+ * 
+ * @since 1.0.0
+ */
+
+public abstract class AbstractJsfConfigurableMockTestCase
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct a new instance of this test case.</p>
+     *
+     * @param name Name of this test case
+     */
+    public AbstractJsfConfigurableMockTestCase()
+    {
+    }
+
+    // ---------------------------------------------------- Overall Test Methods
+
+    /**
+     * <p>Set up instance variables required by this test case.</p>
+     */
+    @Before
+    public void setUp() throws Exception
+    {
+        // Set up a new thread context class loader
+        setUpClassloader();
+
+        // Set up Servlet API Objects
+        setUpServletObjects();
+
+        // Set up JSF API Objects
+        FactoryFinder.releaseFactories();
+
+        setFactories();
+
+        setUpJSFObjects();
+    }
+    
+    /**
+     * Set up the thread context classloader. JSF uses the this classloader
+     * in order to find related factory classes and other resources, but in
+     * some selected cases, the default classloader cannot be properly set.
+     * 
+     * @throws Exception 
+     */
+    protected void setUpClassloader() throws Exception
+    {
+        threadContextClassLoader = Thread.currentThread()
+                .getContextClassLoader();
+        Thread.currentThread()
+                .setContextClassLoader(
+                        new URLClassLoader(new URL[0], this.getClass()
+                                .getClassLoader()));
+        classLoaderSet = true;
+    }
+
+    /**
+     * <p>Setup JSF object used for the test. By default it calls to the following
+     * methods in this order:</p>
+     * 
+     * <ul>
+     * <li><code>setUpExternalContext();</code></li>
+     * <li><code>setUpLifecycle();</code></li>
+     * <li><code>setUpFacesContext();</code></li>
+     * <li><code>setUpView();</code></li>
+     * <li><code>setUpApplication();</code></li>
+     * <li><code>setUpRenderKit();</code></li>
+     * </ul>
+     * 
+     * @throws Exception
+     */
+    protected void setUpJSFObjects() throws Exception
+    {
+        setUpExternalContext();
+        setUpLifecycle();
+        setUpFacesContext();
+        setUpView();
+        setUpApplication();
+        setUpRenderKit();
+    }
+
+    /**
+     * <p>Setup servlet objects that will be used for the test:</p>
+     * 
+     * <ul>
+     * <li><code>config</code> (<code>MockServletConfig</code>)</li>
+     * <li><code>servletContext</code> (<code>MockServletContext</code>)</li>
+     * <li><code>request</code> (<code>MockHttpServletRequest</code></li>
+     * <li><code>response</code> (<code>MockHttpServletResponse</code>)</li>
+     * <li><code>session</code> (<code>MockHttpSession</code>)</li>
+     * </ul>
+     * 
+     * @throws Exception
+     */
+    protected void setUpServletObjects() throws Exception
+    {
+        servletContext = new MockServletContext();
+        config = new MockServletConfig(servletContext);
+        session = new MockHttpSession();
+        session.setServletContext(servletContext);
+        request = new MockHttpServletRequest(session);
+        request.setServletContext(servletContext);
+        response = new MockHttpServletResponse();
+    }
+
+    /**
+     * <p>Set JSF factories using FactoryFinder method setFactory.</p>
+     * 
+     * @throws Exception
+     */
+    protected void setFactories() throws Exception
+    {
+        FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY,
+                "org.apache.myfaces.test.mock.MockApplicationFactory");
+        FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY,
+                "org.apache.myfaces.test.mock.MockFacesContextFactory");
+        FactoryFinder.setFactory(FactoryFinder.LIFECYCLE_FACTORY,
+                "org.apache.myfaces.test.mock.lifecycle.MockLifecycleFactory");
+        FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY,
+                "org.apache.myfaces.test.mock.MockRenderKitFactory");
+        FactoryFinder.setFactory(FactoryFinder.EXCEPTION_HANDLER_FACTORY,
+                "org.apache.myfaces.test.mock.MockExceptionHandlerFactory");
+        FactoryFinder.setFactory(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY,
+                "org.apache.myfaces.test.mock.MockPartialViewContextFactory");
+        FactoryFinder.setFactory(FactoryFinder.VISIT_CONTEXT_FACTORY,
+                "org.apache.myfaces.test.mock.visit.MockVisitContextFactory");
+        FactoryFinder.setFactory(FactoryFinder.CLIENT_WINDOW_FACTORY,
+                "org.apache.myfaces.test.mock.MockClientWindowFactory");
+    }
+
+    /**
+     * Setup the <code>externalContext</code> variable, using the 
+     * servlet variables already initialized.
+     * 
+     * @throws Exception
+     */
+    protected void setUpExternalContext() throws Exception
+    {
+        externalContext = new MockExternalContext(servletContext, request,
+                response);
+    }
+
+    /**
+     * Setup the <code>lifecycle</code> and <code>lifecycleFactory</code>
+     * variables.
+     * 
+     * @throws Exception
+     */
+    protected void setUpLifecycle() throws Exception
+    {
+        lifecycleFactory = (LifecycleFactory) FactoryFinder
+                .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
+        lifecycle = lifecycleFactory
+                .getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
+    }
+
+    /**
+     * Setup the <code>facesContextFactory</code> and <code>facesContext</code>
+     * variable. Before end, by default it override <code>externalContext</code>
+     * variable from the value retrieved from facesContext.getExternalContext(),
+     * because sometimes it is possible facesContext overrides externalContext
+     * internally.
+     * 
+     * @throws Exception
+     */
+    protected void setUpFacesContext() throws Exception
+    {
+        facesContextFactory = (FacesContextFactory) FactoryFinder
+                .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
+        facesContext = (FacesContext) facesContextFactory.getFacesContext(
+                servletContext, request, response, lifecycle);
+        if (facesContext.getExternalContext() != null)
+        {
+            externalContext = facesContext.getExternalContext();
+        }
+    }
+
+    /**
+     * By default, create an instance of UIViewRoot, set its viewId as "/viewId"
+     * and assign it to the current facesContext.
+     * 
+     * @throws Exception
+     */
+    protected void setUpView() throws Exception
+    {
+        UIViewRoot root = new UIViewRoot();
+        root.setViewId("/viewId");
+        root.setRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT);
+        facesContext.setViewRoot(root);
+    }
+
+    /**
+     * Setup the <code>application</code> variable and before
+     * the end by default it is assigned to the <code>facesContext</code>
+     * variable, calling <code>facesContext.setApplication(application)</code>
+     * 
+     * @throws Exception
+     */
+    protected void setUpApplication() throws Exception
+    {
+        ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder
+                .getFactory(FactoryFinder.APPLICATION_FACTORY);
+        application = applicationFactory.getApplication();
+        ((MockFacesContext) facesContext).setApplication(application);
+    }
+
+    /**
+     * Setup the <code>renderKit</code> variable. This is a good place to use
+     * <code>ConfigParser</code> to register converters, validators, components
+     * or renderkits.
+     * 
+     * @throws Exception
+     */
+    protected void setUpRenderKit() throws Exception
+    {
+        RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder
+                .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+        renderKit = new MockRenderKit();
+        renderKitFactory.addRenderKit(RenderKitFactory.HTML_BASIC_RENDER_KIT,
+                renderKit);
+    }
+
+    /**
+     * <p>Tear down instance variables required by this test case.</p>
+     */
+    @After
+    public void tearDown() throws Exception
+    {
+
+        application = null;
+        config = null;
+        externalContext = null;
+        if (facesContext != null)
+        {
+            facesContext.release();
+        }
+        facesContext = null;
+        lifecycle = null;
+        lifecycleFactory = null;
+        renderKit = null;
+        request = null;
+        response = null;
+        servletContext = null;
+        session = null;
+        FactoryFinder.releaseFactories();
+        ResourceBundleVarNames.resetNames();
+
+        tearDownClassloader();
+    }
+    
+    protected void tearDownClassloader() throws Exception
+    {
+        if (classLoaderSet)
+        {
+            Thread.currentThread().setContextClassLoader(threadContextClassLoader);
+            threadContextClassLoader = null;
+            classLoaderSet = false;
+        }
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    // Mock object instances for our tests
+    protected Application application = null;
+    protected MockServletConfig config = null;
+    protected ExternalContext externalContext = null;
+    protected FacesContext facesContext = null;
+    protected FacesContextFactory facesContextFactory = null;
+    protected Lifecycle lifecycle = null;
+    protected LifecycleFactory lifecycleFactory = null;
+    protected RenderKit renderKit = null;
+    protected MockHttpServletRequest request = null;
+    protected MockHttpServletResponse response = null;
+    protected MockServletContext servletContext = null;
+    protected MockHttpSession session = null;
+
+    // Thread context class loader saved and restored after each test
+    private ClassLoader threadContextClassLoader = null;
+    private boolean classLoaderSet = false;
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/base/junit4/AbstractJsfConfigurableMultipleRequestsTestCase.java b/test/src/main/java/org/apache/myfaces/test/base/junit4/AbstractJsfConfigurableMultipleRequestsTestCase.java
new file mode 100644
index 0000000..6e52e3c
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/base/junit4/AbstractJsfConfigurableMultipleRequestsTestCase.java
@@ -0,0 +1,399 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.base.junit4;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import javax.faces.FactoryFinder;
+import javax.faces.application.Application;
+import javax.faces.application.ApplicationFactory;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.context.FacesContextFactory;
+import javax.faces.lifecycle.Lifecycle;
+import javax.faces.lifecycle.LifecycleFactory;
+import javax.faces.render.RenderKit;
+import javax.faces.render.RenderKitFactory;
+
+import org.apache.myfaces.test.config.ResourceBundleVarNames;
+import org.apache.myfaces.test.mock.MockExternalContext;
+import org.apache.myfaces.test.mock.MockFacesContext;
+import org.apache.myfaces.test.mock.MockFacesContextFactory;
+import org.apache.myfaces.test.mock.MockHttpServletRequest;
+import org.apache.myfaces.test.mock.MockHttpServletResponse;
+import org.apache.myfaces.test.mock.MockHttpSession;
+import org.apache.myfaces.test.mock.MockRenderKit;
+import org.apache.myfaces.test.mock.MockServletConfig;
+import org.apache.myfaces.test.mock.MockServletContext;
+import org.apache.myfaces.test.mock.lifecycle.MockLifecycle;
+import org.apache.myfaces.test.mock.lifecycle.MockLifecycleFactory;
+import org.junit.After;
+import org.junit.Before;
+
+/**
+ * <p>Abstract JUnit 4.5 test case base class, which sets up the JavaServer Faces
+ * mock object environment for multiple simulated request.  The following
+ * protected variables are initialized in the <code>setUp()</code> method, and
+ * cleaned up in the <code>tearDown()</code> method:</p>
+ * <ul>
+ * <li><code>application</code> (<code>Application</code>)</li>
+ * <li><code>config</code> (<code>MockServletConfig</code>)</li>
+ * <li><code>externalContext</code> (<code>ExternalContext</code>)</li>
+ * <li><code>facesContext</code> (<code>FacesContext</code>)</li>
+ * <li><code>lifecycle</code> (<code>Lifecycle</code>)</li>
+ * <li><code>request</code> (<code>MockHttpServletRequest</code></li>
+ * <li><code>response</code> (<code>MockHttpServletResponse</code>)</li>
+ * <li><code>servletContext</code> (<code>MockServletContext</code>)</li>
+ * <li><code>session</code> (<code>MockHttpSession</code>)</li>
+ * </ul>
+ *
+ * <p>In addition, appropriate factory classes will have been registered with
+ * <code>javax.faces.FactoryFinder</code> for <code>Application</code> and
+ * <code>RenderKit</code> instances.  The created <code>FacesContext</code>
+ * instance will also have been registered in the proper thread local
+ * variable, to simulate what a servlet container would do.</p>
+ *
+ * <p><strong>WARNING</strong> - If you choose to subclass this class, be sure
+ * your <code>setUp()</code> and <code>tearDown()</code> methods call
+ * <code>super.setUp()</code> and <code>super.tearDown()</code> respectively,
+ * and that you implement your own <code>suite()</code> method that exposes
+ * the test methods for your test case. Additionally, check on each test
+ * that setupRequest() and tearDownRequest() are called correctly.</p>
+ * 
+ * @since 1.0.3
+ */
+
+public abstract class AbstractJsfConfigurableMultipleRequestsTestCase
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct a new instance of this test case.</p>
+     *
+     * @param name Name of this test case
+     */
+    public AbstractJsfConfigurableMultipleRequestsTestCase()
+    {
+    }
+
+    // ---------------------------------------------------- Overall Test Methods
+
+    /**
+     * <p>Set up instance variables required by this test case.</p>
+     */
+    @Before
+    public void setUp() throws Exception
+    {
+        // Set up a new thread context class loader
+        setUpClassloader();
+
+        // Set up JSF Factories
+        FactoryFinder.releaseFactories();
+
+        setFactories();
+
+        // Setup servlet context and session
+        setUpServletContextAndSession();
+        
+        setUpLifecycle();
+        
+        setUpApplication();
+        
+        setUpRenderKit();
+    }
+    
+    /**
+     * Set up the thread context classloader. JSF uses the this classloader
+     * in order to find related factory classes and other resources, but in
+     * some selected cases, the default classloader cannot be properly set.
+     * 
+     * @throws Exception 
+     */
+    protected void setUpClassloader() throws Exception
+    {
+        threadContextClassLoader = Thread.currentThread()
+                .getContextClassLoader();
+        Thread.currentThread()
+                .setContextClassLoader(
+                        new URLClassLoader(new URL[0], this.getClass()
+                                .getClassLoader()));
+        classLoaderSet = true;
+    }
+
+    /**
+     * This method initialize an new empty request.
+     */
+    public void setupRequest() throws Exception
+    {
+        // Set up Servlet API Objects
+        setUpServletRequestAndResponse();
+
+        setUpJSFRequestObjects();
+    }
+
+    /**
+     * <p>Setup JSF object used for the test. By default it calls to the following
+     * methods in this order:</p>
+     * 
+     * <ul>
+     * <li><code>setUpExternalContext();</code></li>
+     * <li><code>setUpLifecycle();</code></li>
+     * <li><code>setUpFacesContext();</code></li>
+     * <li><code>setUpView();</code></li>
+     * <li><code>setUpApplication();</code></li>
+     * <li><code>setUpRenderKit();</code></li>
+     * </ul>
+     * 
+     * @throws Exception
+     */
+    protected void setUpJSFRequestObjects() throws Exception
+    {
+        setUpExternalContext();
+        setUpFacesContext();
+        setUpView();
+    }
+
+    /**
+     * <p>Setup servlet objects that will be used for the test:</p>
+     * 
+     * <ul>
+     * <li><code>config</code> (<code>MockServletConfig</code>)</li>
+     * <li><code>servletContext</code> (<code>MockServletContext</code>)</li>
+     * <li><code>request</code> (<code>MockHttpServletRequest</code></li>
+     * <li><code>response</code> (<code>MockHttpServletResponse</code>)</li>
+     * <li><code>session</code> (<code>MockHttpSession</code>)</li>
+     * </ul>
+     * 
+     * @throws Exception
+     */
+    protected void setUpServletContextAndSession() throws Exception
+    {
+        servletContext = new MockServletContext();
+        config = new MockServletConfig(servletContext);
+        session = new MockHttpSession();
+        session.setServletContext(servletContext);
+    }
+
+    protected void setUpServletRequestAndResponse() throws Exception
+    {
+        request = new MockHttpServletRequest(session);
+        request.setServletContext(servletContext);
+        response = new MockHttpServletResponse();
+    }
+
+    /**
+     * <p>Set JSF factories using FactoryFinder method setFactory.</p>
+     * 
+     * @throws Exception
+     */
+    protected void setFactories() throws Exception
+    {
+        FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY,
+                "org.apache.myfaces.test.mock.MockApplicationFactory");
+        FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY,
+                "org.apache.myfaces.test.mock.MockFacesContextFactory");
+        FactoryFinder.setFactory(FactoryFinder.LIFECYCLE_FACTORY,
+                "org.apache.myfaces.test.mock.lifecycle.MockLifecycleFactory");
+        FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY,
+                "org.apache.myfaces.test.mock.MockRenderKitFactory");
+        FactoryFinder.setFactory(FactoryFinder.EXCEPTION_HANDLER_FACTORY,
+                "org.apache.myfaces.test.mock.MockExceptionHandlerFactory");
+        FactoryFinder.setFactory(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY,
+                "org.apache.myfaces.test.mock.MockPartialViewContextFactory");
+        FactoryFinder.setFactory(FactoryFinder.VISIT_CONTEXT_FACTORY,
+                "org.apache.myfaces.test.mock.visit.MockVisitContextFactory");
+        FactoryFinder.setFactory(FactoryFinder.CLIENT_WINDOW_FACTORY,
+                "org.apache.myfaces.test.mock.MockClientWindowFactory");
+    }
+
+    /**
+     * Setup the <code>externalContext</code> variable, using the 
+     * servlet variables already initialized.
+     * 
+     * @throws Exception
+     */
+    protected void setUpExternalContext() throws Exception
+    {
+        externalContext = new MockExternalContext(servletContext, request,
+                response);
+    }
+
+    /**
+     * Setup the <code>lifecycle</code> and <code>lifecycleFactory</code>
+     * variables.
+     * 
+     * @throws Exception
+     */
+    protected void setUpLifecycle() throws Exception
+    {
+        lifecycleFactory = (MockLifecycleFactory) FactoryFinder
+                .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
+        lifecycle = (MockLifecycle) lifecycleFactory
+                .getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
+    }
+
+    /**
+     * Setup the <code>facesContextFactory</code> and <code>facesContext</code>
+     * variable. Before end, by default it override <code>externalContext</code>
+     * variable from the value retrieved from facesContext.getExternalContext(),
+     * because sometimes it is possible facesContext overrides externalContext
+     * internally.
+     * 
+     * @throws Exception
+     */
+    protected void setUpFacesContext() throws Exception
+    {
+        facesContextFactory = (MockFacesContextFactory) FactoryFinder
+                .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
+        facesContext = (MockFacesContext) facesContextFactory.getFacesContext(
+                servletContext, request, response, lifecycle);
+        if (facesContext.getExternalContext() != null)
+        {
+            externalContext = (MockExternalContext) facesContext
+                    .getExternalContext();
+        }
+        if (facesContext instanceof MockFacesContext)
+        {
+            ((MockFacesContext) facesContext).setApplication(application);
+        }
+    }
+
+    /**
+     * By default, create an instance of UIViewRoot, set its viewId as "/viewId"
+     * and assign it to the current facesContext.
+     * 
+     * @throws Exception
+     */
+    protected void setUpView() throws Exception
+    {
+        UIViewRoot root = new UIViewRoot();
+        root.setViewId("/viewId");
+        root.setRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT);
+        facesContext.setViewRoot(root);
+    }
+
+    /**
+     * Setup the <code>application</code> variable and before
+     * the end by default it is assigned to the <code>facesContext</code>
+     * variable, calling <code>facesContext.setApplication(application)</code>
+     * 
+     * @throws Exception
+     */
+    protected void setUpApplication() throws Exception
+    {
+        ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder
+                .getFactory(FactoryFinder.APPLICATION_FACTORY);
+        application = applicationFactory.getApplication();
+    }
+
+    /**
+     * Setup the <code>renderKit</code> variable. This is a good place to use
+     * <code>ConfigParser</code> to register converters, validators, components
+     * or renderkits.
+     * 
+     * @throws Exception
+     */
+    protected void setUpRenderKit() throws Exception
+    {
+        RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder
+                .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+        renderKit = new MockRenderKit();
+        renderKitFactory.addRenderKit(RenderKitFactory.HTML_BASIC_RENDER_KIT,
+            renderKit);
+    }
+
+    /**
+     * <p>Tear down instance variables required by this test case.</p>
+     */
+    @After
+    public void tearDown() throws Exception
+    {
+
+        application = null;
+        config = null;
+        externalContext = null;
+        if (facesContext != null)
+        {
+            facesContext.release();
+        }
+        facesContext = null;
+        lifecycle = null;
+        lifecycleFactory = null;
+        renderKit = null;
+        request = null;
+        response = null;
+        servletContext = null;
+        session = null;
+        FactoryFinder.releaseFactories();
+        ResourceBundleVarNames.resetNames();
+
+        tearDownClassloader();
+    }
+    
+    protected void tearDownClassloader() throws Exception
+    {
+        if (classLoaderSet)
+        {
+            Thread.currentThread().setContextClassLoader(threadContextClassLoader);
+            threadContextClassLoader = null;
+            classLoaderSet = false;
+        }
+    }
+
+    
+    /**
+     * This method ends the current request.
+     */
+    public void tearDownRequest()
+    {
+        externalContext = null;
+        if (facesContext != null)
+        {
+            facesContext.release();
+        }
+        facesContext = null;
+        request = null;
+        response = null;
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    // Mock object instances for our tests
+    protected Application application = null;
+    protected MockServletConfig config = null;
+    protected ExternalContext externalContext = null;
+    protected FacesContext facesContext = null;
+    protected FacesContextFactory facesContextFactory = null;
+    protected Lifecycle lifecycle = null;
+    protected LifecycleFactory lifecycleFactory = null;
+    protected RenderKit renderKit = null;
+    protected MockHttpServletRequest request = null;
+    protected MockHttpServletResponse response = null;
+    protected MockServletContext servletContext = null;
+    protected MockHttpSession session = null;
+
+    // Thread context class loader saved and restored after each test
+    private ClassLoader threadContextClassLoader = null;
+    private boolean classLoaderSet = false;
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/base/junit4/AbstractJsfTestCase.java b/test/src/main/java/org/apache/myfaces/test/base/junit4/AbstractJsfTestCase.java
new file mode 100644
index 0000000..78f6694
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/base/junit4/AbstractJsfTestCase.java
@@ -0,0 +1,360 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.base.junit4;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import javax.faces.FactoryFinder;
+import javax.faces.application.ApplicationFactory;
+import javax.faces.component.UIViewRoot;
+import javax.faces.lifecycle.LifecycleFactory;
+import javax.faces.render.RenderKitFactory;
+
+import org.apache.myfaces.test.config.ResourceBundleVarNames;
+import org.apache.myfaces.test.mock.MockApplication;
+import org.apache.myfaces.test.mock.MockExternalContext;
+import org.apache.myfaces.test.mock.MockFacesContext;
+import org.apache.myfaces.test.mock.MockFacesContextFactory;
+import org.apache.myfaces.test.mock.MockHttpServletRequest;
+import org.apache.myfaces.test.mock.MockHttpServletResponse;
+import org.apache.myfaces.test.mock.MockHttpSession;
+import org.apache.myfaces.test.mock.MockRenderKit;
+import org.apache.myfaces.test.mock.MockServletConfig;
+import org.apache.myfaces.test.mock.MockServletContext;
+import org.apache.myfaces.test.mock.lifecycle.MockLifecycle;
+import org.apache.myfaces.test.mock.lifecycle.MockLifecycleFactory;
+import org.junit.After;
+import org.junit.Before;
+
+/**
+ * <p>Abstract JUnit 4.5 test case base class, which sets up the JavaServer Faces
+ * mock object environment for a particular simulated request.  The following
+ * protected variables are initialized in the <code>setUp()</code> method, and
+ * cleaned up in the <code>tearDown()</code> method:</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>MockHttpServletResponse</code>)</li>
+ * <li><code>servletContext</code> (<code>MockServletContext</code>)</li>
+ * <li><code>session</code> (<code>MockHttpSession</code>)</li>
+ * </ul>
+ *
+ * <p>In addition, appropriate factory classes will have been registered with
+ * <code>javax.faces.FactoryFinder</code> for <code>Application</code> and
+ * <code>RenderKit</code> instances.  The created <code>FacesContext</code>
+ * instance will also have been registered in the apppriate thread local
+ * variable, to simulate what a servlet container would do.</p>
+ *
+ * <p><strong>WARNING</strong> - If you choose to subclass this class, be sure
+ * your <code>setUp()</code> and <code>tearDown()</code> methods call
+ * <code>super.setUp()</code> and <code>super.tearDown()</code> respectively,
+ * and that you implement your own <code>suite()</code> method that exposes
+ * the test methods for your test case.</p>
+ * 
+ * @since 1.0.0
+ */
+
+public abstract class AbstractJsfTestCase
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct a new instance of this test case.</p>
+     *
+     * @param name Name of this test case
+     */
+    public AbstractJsfTestCase()
+    {
+    }
+
+    // ---------------------------------------------------- Overall Test Methods
+
+    /**
+     * <p>Set up instance variables required by this test case.</p>
+     */
+    @Before
+    public void setUp() throws Exception
+    {
+
+        // Set up a new thread context class loader
+        setUpClassloader();
+
+        // Set up Servlet API Objects
+        setUpServletObjects();
+
+        // Set up JSF API Objects
+        FactoryFinder.releaseFactories();
+
+        setFactories();
+
+        setUpJSFObjects();
+    }
+
+    /**
+     * Set up the thread context classloader. JSF uses the this classloader
+     * in order to find related factory classes and other resources, but in
+     * some selected cases, the default classloader cannot be properly set.
+     * 
+     * @throws Exception 
+     */
+    protected void setUpClassloader() throws Exception
+    {
+        threadContextClassLoader = Thread.currentThread()
+                .getContextClassLoader();
+        Thread.currentThread()
+                .setContextClassLoader(
+                        new URLClassLoader(new URL[0], this.getClass()
+                                .getClassLoader()));
+        classLoaderSet = true;
+    }
+
+    /**
+     * <p>Setup JSF object used for the test. By default it calls to the following
+     * methods in this order:</p>
+     * 
+     * <ul>
+     * <li><code>setUpExternalContext();</code></li>
+     * <li><code>setUpLifecycle();</code></li>
+     * <li><code>setUpFacesContext();</code></li>
+     * <li><code>setUpView();</code></li>
+     * <li><code>setUpApplication();</code></li>
+     * <li><code>setUpRenderKit();</code></li>
+     * </ul>
+     * 
+     * @throws Exception
+     */
+    protected void setUpJSFObjects() throws Exception
+    {
+        setUpExternalContext();
+        setUpLifecycle();
+        setUpFacesContext();
+        setUpView();
+        setUpApplication();
+        setUpRenderKit();
+    }
+
+    /**
+     * <p>Setup servlet objects that will be used for the test:</p>
+     * 
+     * <ul>
+     * <li><code>config</code> (<code>MockServletConfig</code>)</li>
+     * <li><code>servletContext</code> (<code>MockServletContext</code>)</li>
+     * <li><code>request</code> (<code>MockHttpServletRequest</code></li>
+     * <li><code>response</code> (<code>MockHttpServletResponse</code>)</li>
+     * <li><code>session</code> (<code>MockHttpSession</code>)</li>
+     * </ul>
+     * 
+     * @throws Exception
+     */
+    protected void setUpServletObjects() throws Exception
+    {
+        servletContext = new MockServletContext();
+        config = new MockServletConfig(servletContext);
+        session = new MockHttpSession();
+        session.setServletContext(servletContext);
+        request = new MockHttpServletRequest(session);
+        request.setServletContext(servletContext);
+        response = new MockHttpServletResponse();
+    }
+
+    /**
+     * <p>Set JSF factories using FactoryFinder method setFactory.</p>
+     * 
+     * @throws Exception
+     */
+    protected void setFactories() throws Exception
+    {
+        FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY,
+                "org.apache.myfaces.test.mock.MockApplicationFactory");
+        FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY,
+                "org.apache.myfaces.test.mock.MockFacesContextFactory");
+        FactoryFinder.setFactory(FactoryFinder.LIFECYCLE_FACTORY,
+                "org.apache.myfaces.test.mock.lifecycle.MockLifecycleFactory");
+        FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY,
+                "org.apache.myfaces.test.mock.MockRenderKitFactory");
+        FactoryFinder.setFactory(FactoryFinder.EXCEPTION_HANDLER_FACTORY,
+                "org.apache.myfaces.test.mock.MockExceptionHandlerFactory");
+        FactoryFinder.setFactory(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY,
+                "org.apache.myfaces.test.mock.MockPartialViewContextFactory");
+        FactoryFinder.setFactory(FactoryFinder.VISIT_CONTEXT_FACTORY,
+                "org.apache.myfaces.test.mock.visit.MockVisitContextFactory");
+        FactoryFinder.setFactory(FactoryFinder.CLIENT_WINDOW_FACTORY,
+                "org.apache.myfaces.test.mock.MockClientWindowFactory");
+    }
+
+    /**
+     * Setup the <code>externalContext</code> variable, using the 
+     * servlet variables already initialized.
+     * 
+     * @throws Exception
+     */
+    protected void setUpExternalContext() throws Exception
+    {
+        externalContext = new MockExternalContext(servletContext, request,
+                response);
+    }
+
+    /**
+     * Setup the <code>lifecycle</code> and <code>lifecycleFactory</code>
+     * variables.
+     * 
+     * @throws Exception
+     */
+    protected void setUpLifecycle() throws Exception
+    {
+        lifecycleFactory = (MockLifecycleFactory) FactoryFinder
+                .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
+        lifecycle = (MockLifecycle) lifecycleFactory
+                .getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
+    }
+
+    /**
+     * Setup the <code>facesContextFactory</code> and <code>facesContext</code>
+     * variable. Before end, by default it override <code>externalContext</code>
+     * variable from the value retrieved from facesContext.getExternalContext(),
+     * because sometimes it is possible facesContext overrides externalContext
+     * internally.
+     * 
+     * @throws Exception
+     */
+    protected void setUpFacesContext() throws Exception
+    {
+        facesContextFactory = (MockFacesContextFactory) FactoryFinder
+                .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
+        facesContext = (MockFacesContext) facesContextFactory.getFacesContext(
+                servletContext, request, response, lifecycle);
+        if (facesContext.getExternalContext() != null)
+        {
+            externalContext = (MockExternalContext) facesContext
+                    .getExternalContext();
+        }
+    }
+
+    /**
+     * By default, create an instance of UIViewRoot, set its viewId as "/viewId"
+     * and assign it to the current facesContext.
+     * 
+     * @throws Exception
+     */
+    protected void setUpView() throws Exception
+    {
+        UIViewRoot root = new UIViewRoot();
+        root.setViewId("/viewId");
+        root.setRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT);
+        facesContext.setViewRoot(root);
+    }
+
+    /**
+     * Setup the <code>application</code> variable and before
+     * the end by default it is assigned to the <code>facesContext</code>
+     * variable, calling <code>facesContext.setApplication(application)</code>
+     * 
+     * @throws Exception
+     */
+    protected void setUpApplication() throws Exception
+    {
+        ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder
+                .getFactory(FactoryFinder.APPLICATION_FACTORY);
+        application = (MockApplication) applicationFactory.getApplication();
+        facesContext.setApplication(application);
+    }
+
+    /**
+     * Setup the <code>renderKit</code> variable. This is a good place to use
+     * <code>ConfigParser</code> to register converters, validators, components
+     * or renderkits.
+     * 
+     * @throws Exception
+     */
+    protected void setUpRenderKit() throws Exception
+    {
+        RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder
+                .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+        renderKit = new MockRenderKit();
+        renderKitFactory.addRenderKit(RenderKitFactory.HTML_BASIC_RENDER_KIT,
+                renderKit);
+    }
+
+    /**
+     * <p>Tear down instance variables required by this test case.</p>
+     */
+    @After
+    public void tearDown() throws Exception
+    {
+
+        application = null;
+        config = null;
+        externalContext = null;
+        if (facesContext != null)
+        {
+            facesContext.release();
+        }
+        facesContext = null;
+        lifecycle = null;
+        lifecycleFactory = null;
+        renderKit = null;
+        request = null;
+        response = null;
+        servletContext = null;
+        session = null;
+        FactoryFinder.releaseFactories();
+        ResourceBundleVarNames.resetNames();
+
+        tearDownClassloader();
+
+    }
+    
+    protected void tearDownClassloader() throws Exception
+    {
+        if (classLoaderSet)
+        {
+            Thread.currentThread().setContextClassLoader(threadContextClassLoader);
+            threadContextClassLoader = null;
+            classLoaderSet = false;
+        }
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    // Mock object instances for our tests
+    protected MockApplication application = null;
+    protected MockServletConfig config = null;
+    protected MockExternalContext externalContext = null;
+    protected MockFacesContext facesContext = null;
+    protected MockFacesContextFactory facesContextFactory = null;
+    protected MockLifecycle lifecycle = null;
+    protected MockLifecycleFactory lifecycleFactory = null;
+    protected MockRenderKit renderKit = null;
+    protected MockHttpServletRequest request = null;
+    protected MockHttpServletResponse response = null;
+    protected MockServletContext servletContext = null;
+    protected MockHttpSession session = null;
+
+    // Thread context class loader saved and restored after each test
+    private ClassLoader threadContextClassLoader = null;
+    private boolean classLoaderSet = false;
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/base/junit4/AbstractViewControllerTestCase.java b/test/src/main/java/org/apache/myfaces/test/base/junit4/AbstractViewControllerTestCase.java
new file mode 100644
index 0000000..2f2e7c2
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/base/junit4/AbstractViewControllerTestCase.java
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.base.junit4;
+
+import java.util.Iterator;
+
+import org.junit.Assert;
+
+/**
+ * <p>Abstract base class for testing <code>ViewController</code>
+ * implementations.</p>
+ *
+ * <p><strong>WARNING</strong> - If you choose to subclass this class, be sure
+ * your <code>setUp()</code> and <code>tearDown()</code> methods call
+ * <code>super.setUp()</code> and <code>super.tearDown()</code> respectively,
+ * and that you implement your own <code>suite()</code> method that exposes
+ * the test methods for your test case.</p>
+ * 
+ * @since 1.0.0
+ */
+public abstract class AbstractViewControllerTestCase extends
+        AbstractJsfTestCase
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct a new instance of this test case.</p>
+     *
+     * @param name Test case name
+     */
+    public AbstractViewControllerTestCase()
+    {
+        super();
+    }
+
+    // ---------------------------------------------------- Overall Test Methods
+
+    // ------------------------------------------------------ Instance Variables
+
+    // ------------------------------------------------------- Protected Methods
+
+    /**
+     * <p>Test that the specified number of messages have been queued on the
+     * <code>FacesContext</code> instance, without regard to matching a
+     * particular client identifier.</p>
+     *
+     * @param expected The expected number of messages
+     */
+    protected void checkMessageCount(int expected)
+    {
+
+        int actual = 0;
+        Iterator messages = facesContext.getMessages();
+        while (messages.hasNext())
+        {
+            messages.next();
+            actual++;
+        }
+        Assert.assertEquals("Complete message count", expected, actual);
+
+    }
+
+    /**
+     * <p>Test that the specified number of messages have been queued on the
+     * <code>FacesContext</code> instance, for the specified client id.</p>
+     *
+     * @param clientId Client identifier of the component for which to
+     *  count queued messages
+     * @param expected The expected number of messages
+     */
+    protected void checkMessageCount(String clientId, int expected)
+    {
+
+        int actual = 0;
+        Iterator messages = facesContext.getMessages(clientId);
+        while (messages.hasNext())
+        {
+            messages.next();
+            actual++;
+        }
+        Assert.assertEquals("Complete message count", expected, actual);
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/cargo/CargoTestSetup.java b/test/src/main/java/org/apache/myfaces/test/cargo/CargoTestSetup.java
new file mode 100644
index 0000000..103fe4f
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/cargo/CargoTestSetup.java
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.cargo;
+
+import java.io.File;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+
+import org.codehaus.cargo.container.InstalledLocalContainer;
+import org.codehaus.cargo.container.ContainerType;
+import org.codehaus.cargo.container.tomcat.Tomcat5xInstalledLocalContainer;
+import org.codehaus.cargo.container.deployable.Deployable;
+import org.codehaus.cargo.container.deployable.DeployableType;
+import org.codehaus.cargo.container.configuration.LocalConfiguration;
+import org.codehaus.cargo.container.configuration.ConfigurationType;
+import org.codehaus.cargo.generic.deployable.DefaultDeployableFactory;
+import org.codehaus.cargo.generic.configuration.ConfigurationFactory;
+import org.codehaus.cargo.generic.configuration.DefaultConfigurationFactory;
+import org.codehaus.cargo.generic.DefaultContainerFactory;
+import org.codehaus.cargo.util.log.FileLogger;
+
+/**
+ * <p>Convenience <code>TestSetup</code> class which uses Cargo to start
+ * and stop a Servlet container.</p>
+ * 
+ * @since 1.0.0
+ */
+public class CargoTestSetup extends TestSetup
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct a new instance of this test setup.</p>
+     *
+     * @param test Tests to be run within this test setup.
+     */
+    public CargoTestSetup(Test test)
+    {
+        super(test);
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>The installed local container for this test setup.</p>
+     */
+    private InstalledLocalContainer container;
+
+    // ------------------------------------------------------ Test Setup Methods
+
+    /**
+     * <p>Start the container prior to running the tests.</p>
+     * <p>The following System properties are used:
+     * <ul>
+     * <li>cargo.container.id - ID of the container to use. [tomcat5x]</li>
+     * <li>cargo.container.home - Full path to a local installation of the container.
+     * If not set, uses the value of the TOMCAT_HOME environment variable.
+     * One of cargo.container.home or TOMCAT_HOME is REQUIRED.</li>
+     * <li>cargo.deployable - Full path to the war file to deploy. REQUIRED.</li>
+     * <li>cargo.container.output - Full path to a file to use for output. [none]</li>
+     * <li>cargo.container.log - Full path to a file to use for logging. [none]</li>
+     * <li>cargo.servlet.port - The port on which the container should listen. [8080]</li>
+     * </ul>
+     * </p>
+     *
+     * @throws Exception if an error occurs.
+     */
+    protected void setUp() throws Exception
+    {
+
+        super.setUp();
+
+        // If there is no container id, default to Tomcat 5x
+        String containerId = System.getProperty("cargo.container.id");
+        if (containerId == null)
+        {
+            containerId = Tomcat5xInstalledLocalContainer.ID;
+        }
+        System.out.println("[INFO] container id: " + containerId);
+
+        // Construct the war, using the container id and the path to the war file
+        String deployablePath = System.getProperty("cargo.deployable");
+        System.out.println("[INFO] deployable: " + deployablePath);
+        Deployable war = new DefaultDeployableFactory().createDeployable(
+                containerId, deployablePath, DeployableType.WAR);
+
+        // Container configuration
+        ConfigurationFactory configurationFactory = new DefaultConfigurationFactory();
+
+        LocalConfiguration configuration = (LocalConfiguration) configurationFactory
+                .createConfiguration(containerId, ConfigurationType.STANDALONE);
+
+        // Find and (if provided) set the port to use for the container.
+        String servletPort = System.getProperty("cargo.servlet.port");
+        if (servletPort != null)
+        {
+            configuration.setProperty("cargo.servlet.port", servletPort);
+            System.out.println("[INFO] servlet port: " + servletPort);
+        }
+
+        configuration.addDeployable(war);
+
+        container = (InstalledLocalContainer) new DefaultContainerFactory()
+                .createContainer(containerId, ContainerType.INSTALLED,
+                        configuration);
+
+        // If 'cargo.container.home' is not set, or if an expression was
+        // passed through, try to use the TOMCAT_HOME environment variable.
+        String containerHome = System.getProperty("cargo.container.home");
+        if (containerHome == null || containerHome.startsWith("$"))
+        {
+            containerHome = System.getenv("TOMCAT_HOME");
+        }
+        System.out.println("[INFO] container home: " + containerHome);
+        container.setHome(new File(containerHome));
+
+        // Find and (if provided) set the path to a log file
+        String containerLog = System.getProperty("cargo.container.log");
+        if (containerLog != null)
+        {
+            System.out.println("[INFO] container log: " + containerLog);
+            container.setLogger(new FileLogger(containerLog, false));
+        }
+
+        // Find and (if provided) set the path to an output file
+        String containerOutput = System.getProperty("cargo.container.output");
+        if (containerOutput != null)
+        {
+            System.out.println("[INFO] container output: " + containerOutput);
+            container.setOutput(new File(containerOutput));
+        }
+
+        container.start();
+    }
+
+    /**
+     * Stop the container after running the tests.
+     *
+     * @throws Exception if an error occurs.
+     */
+    protected void tearDown() throws Exception
+    {
+        container.stop();
+        super.tearDown();
+    }
+
+    /**
+     * Return the name of the test setup.
+     * (Temporarily required due to MSUREFIRE-119.)
+     *
+     * @return the name of the test setup.
+     * @deprecated No replacement.
+     */
+
+    public String getName()
+    {
+        return "CargoTestSetup";
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/config/ConfigParser.java b/test/src/main/java/org/apache/myfaces/test/config/ConfigParser.java
new file mode 100644
index 0000000..b0ce0d6
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/config/ConfigParser.java
@@ -0,0 +1,709 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.config;
+
+import java.io.IOException;
+import java.net.URL;
+
+import javax.faces.FactoryFinder;
+import javax.faces.application.Application;
+import javax.faces.application.ApplicationFactory;
+import javax.faces.render.ClientBehaviorRenderer;
+import javax.faces.render.RenderKit;
+import javax.faces.render.RenderKitFactory;
+import javax.faces.render.Renderer;
+
+import org.apache.commons.digester.Digester;
+import org.apache.commons.digester.Rule;
+import org.apache.myfaces.test.mock.MockRenderKit;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * <p>Utility class to parse JavaServer Faces configuration resources, and
+ * register JSF artifacts with the mock object hierarchy.</p>
+ *
+ * <p>The following artifacts are registered:</p>
+ * <ul>
+ *     <li><code>Converter</code> (by-id and by-class)</li>
+ *     <li><code>RenderKit</code> and <code>Renderer</code>,<code>ClientBehaviorRenderer</code></li>
+ *     <li><code>UIComponent</code></li>
+ *     <li><code>Validator</code></li>
+ *     <li><code>Behavior</code></li>
+ * </ul>
+ *
+ * <p>Note that any declared <em>factory</em> instances are explicitly
+ * <strong>NOT</strong> registered, allowing the mock object hierarchy
+ * of the Myfaces Test Framework to manage these APIs.</p>
+ *
+ * <p><strong>USAGE NOTE</strong> - If you are using an instance of this
+ * class within a subclass of <code>AbstractJsfTestCase</code> or
+ * <code>AbstractJmockJsfTestCase</code>, be sure you have completed the
+ * <code>setUp()</code> processing in this base class before calling one
+ * of the <code>parse()</code> methods.</p>
+ *
+ * @since 1.0.0
+ */
+public class ConfigParser
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /** Creates a new instance of ConfigParser */
+    public ConfigParser()
+    {
+    }
+
+    // ------------------------------------------------------ Manifest Constants
+
+    /**
+     * <p>Configuration resource URLs for the JSF RI.</p>
+     */
+    private static final String[] JSFRI_RESOURCES = { "/com/sun/faces/jsf-ri-runtime.xml", };
+
+    /**
+     * <p>Configuration resource URLs for Apache MyFaces.</p>
+     */
+    private static final String[] MYFACES_RESOURCES = { "/org/apache/myfaces/resource/standard-faces-config.xml", };
+
+    /**
+     * <p>Configuration resource URLs for Apache MyFaces 1.2.</p>
+     */
+    private static final String[] MYFACES_RESOURCES12 = { "/META-INF/standard-faces-config.xml", };
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>The <code>Digester</code> instance we will use for parsing.</p>
+     */
+    private Digester digester = null;
+
+    // ------------------------------------------------------- Public Properties
+
+    /**
+     * <p>Return the URLs of the platform configuration resources for this
+     * application.  The following platforms are currently supported:</p>
+     * <ul>
+     * <li>JavaServer Faces Reference Implementation (version 1.0 - 1.2)</li>
+     * <li>MyFaces (version 1.1)</li>
+     * </ul>
+     *
+     * <p>If MyFaces (version 1.2), currently under development, does not change
+     * the name of the configuration resource, it will be supported as well.</p>
+     */
+    public URL[] getPlatformURLs()
+    {
+
+        URL[] urls = translate(JSFRI_RESOURCES);
+        if (urls[0] == null)
+        {
+            urls = translate(MYFACES_RESOURCES12);
+            if (urls[0] == null)
+            {
+                urls = translate(MYFACES_RESOURCES);
+            }
+        }
+        return urls;
+
+    }
+
+    // ---------------------------------------------------------- Public Methods
+
+    /**
+     * <p>Parse the specified JavaServer Faces configuration resource, causing
+     * the appropriate JSF artifacts to be registered with the mock object
+     * hierarchy.</p>
+     *
+     * @param url <code>URL</code> of the configuration resource to parse
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception SAXException if a parsing error occurs
+     */
+    public void parse(URL url) throws IOException, SAXException
+    {
+
+        // Acquire and configure the Digester instance we will use
+        Digester digester = digester();
+        ApplicationFactory factory = (ApplicationFactory) FactoryFinder
+                .getFactory(FactoryFinder.APPLICATION_FACTORY);
+        Application application = factory.getApplication();
+        digester.push(application);
+
+        // Perform the required parsing
+        try
+        {
+            digester.parse(url);
+        }
+        finally
+        {
+            digester.clear();
+        }
+
+    }
+
+    /**
+     * <p>Parse the specified set of JavaServer Faces configuration resources,
+     * in the listed order, causing the appropriate JSF artifacts to be registered
+     * with the mock object hierarchy.</p>
+     *
+     * @param urls <code>URL</code>s of the configuration resources to parse
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception SAXException if a parsing error occurs
+     */
+    public void parse(URL[] urls) throws IOException, SAXException
+    {
+
+        for (int i = 0; i < urls.length; i++)
+        {
+            parse(urls[i]);
+        }
+
+    }
+
+    // --------------------------------------------------------- Private Methods
+
+    /**
+     * <p>Return the <code>Digester</code> instance we will use for parsing,
+     * creating and configuring a new instance if necessary.</p>
+     */
+    private Digester digester()
+    {
+
+        if (this.digester == null)
+        {
+            this.digester = new Digester();
+            digester.addRule("faces-config/component", new ComponentRule());
+            digester.addCallMethod("faces-config/component/component-type",
+                    "setComponentType", 0);
+            digester.addCallMethod("faces-config/component/component-class",
+                    "setComponentClass", 0);
+            digester.addRule("faces-config/converter", new ConverterRule());
+            digester.addCallMethod("faces-config/converter/converter-id",
+                    "setConverterId", 0);
+            digester.addCallMethod("faces-config/converter/converter-class",
+                    "setConverterClass", 0);
+            digester.addCallMethod(
+                    "faces-config/converter/converter-for-class",
+                    "setConverterForClass", 0);
+            digester.addRule("faces-config/render-kit", new RenderKitRule());
+            digester.addRule("faces-config/render-kit/render-kit-id",
+                    new RenderKitIdRule());
+            digester.addRule("faces-config/render-kit/renderer",
+                    new RendererRule());
+            digester.addCallMethod(
+                    "faces-config/render-kit/renderer/component-family",
+                    "setComponentFamily", 0);
+            digester.addCallMethod(
+                    "faces-config/render-kit/renderer/renderer-class",
+                    "setRendererClass", 0);
+            digester.addCallMethod(
+                    "faces-config/render-kit/renderer/renderer-type",
+                    "setRendererType", 0);
+            digester.addRule(
+                    "faces-config/render-kit/client-behavior-renderer",
+                    new ClientBehaviorRendererRule());
+            digester
+                    .addCallMethod(
+                            "faces-config/render-kit/client-behavior-renderer/client-behavior-renderer-type",
+                            "setClientBehaviorRendererType", 0);
+            digester
+                    .addCallMethod(
+                            "faces-config/render-kit/client-behavior-renderer/client-behavior-renderer-class",
+                            "setClientBehaviorRendererClass", 0);
+            digester.addRule("faces-config/validator", new ValidatorRule());
+            digester.addCallMethod("faces-config/validator/validator-id",
+                    "setValidatorId", 0);
+            digester.addCallMethod("faces-config/validator/validator-class",
+                    "setValidatorClass", 0);
+            digester.addRule("faces-config/behavior", new BehaviorRule());
+            digester.addCallMethod("faces-config/behavior/behavior-id",
+                    "setBehaviorId", 0);
+            digester.addCallMethod("faces-config/behavior/behavior-class",
+                    "setBehaviorClass", 0);
+        }
+        return this.digester;
+
+    }
+
+    /**
+     * <p>Translate an array of resource names into an array of resource URLs.</p>
+     *
+     * @param names Resource names to translate
+     */
+    private URL[] translate(String[] names)
+    {
+
+        URL[] results = new URL[names.length];
+        for (int i = 0; i < names.length; i++)
+        {
+            results[i] = this.getClass().getResource(names[i]);
+        }
+        return results;
+
+    }
+
+    // --------------------------------------------------------- Private Classes
+
+    /**
+     * <p>Data bean that stores information related to a component.</p>
+     */
+    class ComponentBean
+    {
+
+        private String componentClass;
+
+        public String getComponentClass()
+        {
+            return this.componentClass;
+        }
+
+        public void setComponentClass(String componentClass)
+        {
+            this.componentClass = componentClass;
+        }
+
+        private String componentType;
+
+        public String getComponentType()
+        {
+            return this.componentType;
+        }
+
+        public void setComponentType(String componentType)
+        {
+            this.componentType = componentType;
+        }
+
+    }
+
+    /**
+     * <p>Digester <code>Rule</code> for processing components.</p>
+     */
+    class ComponentRule extends Rule
+    {
+
+        public void begin(String namespace, String name, Attributes attributes)
+        {
+            getDigester().push(new ComponentBean());
+        }
+
+        public void end(String namespace, String name)
+        {
+            ComponentBean bean = (ComponentBean) getDigester().pop();
+            Application application = (Application) getDigester().peek();
+            application.addComponent(bean.getComponentType(), bean
+                    .getComponentClass());
+        }
+
+    }
+
+    /**
+     * <p>Data bean that stores information related to a converter.</p>
+     */
+    class ConverterBean
+    {
+
+        private String converterClass;
+
+        public String getConverterClass()
+        {
+            return this.converterClass;
+        }
+
+        public void setConverterClass(String converterClass)
+        {
+            this.converterClass = converterClass;
+        }
+
+        private String converterForClass;
+
+        public String getConverterForClass()
+        {
+            return this.converterForClass;
+        }
+
+        public void setConverterForClass(String converterForClass)
+        {
+            this.converterForClass = converterForClass;
+        }
+
+        private String converterId;
+
+        public String getConverterId()
+        {
+            return this.converterId;
+        }
+
+        public void setConverterId(String converterId)
+        {
+            this.converterId = converterId;
+        }
+
+    }
+
+    /**
+     * <p>Digester <code>Rule</code> for processing converers.</p>
+     */
+    class ConverterRule extends Rule
+    {
+
+        public void begin(String namespace, String name, Attributes attributes)
+        {
+            getDigester().push(new ConverterBean());
+        }
+
+        public void end(String namespace, String name)
+        {
+            ConverterBean bean = (ConverterBean) getDigester().pop();
+            Application application = (Application) getDigester().peek();
+            if (bean.getConverterId() != null)
+            {
+                application.addConverter(bean.getConverterId(), bean
+                        .getConverterClass());
+            }
+            else
+            {
+                Class clazz = null;
+                try
+                {
+                    clazz = classForName(bean.getConverterForClass());
+                }
+                catch (ClassNotFoundException e)
+                {
+                    throw new IllegalArgumentException(
+                            "java.lang.ClassNotFoundException: "
+                                    + bean.getConverterForClass());
+                }
+                application.addConverter(clazz, bean.getConverterClass());
+            }
+        }
+
+    }
+
+    private Class classForName(String type) throws ClassNotFoundException
+    {
+        try
+        {
+            // Try WebApp ClassLoader first
+            return Class.forName(type, false, // do not initialize for faster startup
+                    Thread.currentThread().getContextClassLoader());
+        }
+        catch (ClassNotFoundException ignore)
+        {
+            // fallback: Try ClassLoader for ClassUtils (i.e. the myfaces.jar lib)
+            return Class.forName(type, false, // do not initialize for faster startup
+                    this.getClass().getClassLoader());
+        }
+    }
+
+    /**
+     * <p>Digester <code>Rule</code> for processing render kits.</p>
+     */
+    class RenderKitRule extends Rule
+    {
+
+        public void begin(String namespace, String name, Attributes attributes)
+        {
+            RenderKitFactory factory = (RenderKitFactory) FactoryFinder
+                    .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+            getDigester().push(
+                    factory.getRenderKit(null,
+                            RenderKitFactory.HTML_BASIC_RENDER_KIT));
+        }
+
+        public void end(String namespace, String name)
+        {
+            getDigester().pop();
+        }
+
+    }
+
+    /**
+     * <p>Digester <code>Rule</code> for processing render kit identifiers.</p>
+     */
+    class RenderKitIdRule extends Rule
+    {
+
+        public void body(String namespace, String name, String text)
+        {
+            String renderKitId = text.trim();
+            RenderKitFactory factory = (RenderKitFactory) FactoryFinder
+                    .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+            RenderKit renderKit = factory.getRenderKit(null, renderKitId);
+            if (renderKit == null)
+            {
+                renderKit = new MockRenderKit();
+                factory.addRenderKit(renderKitId, renderKit);
+            }
+            getDigester().pop();
+            getDigester().push(renderKit);
+        }
+
+    }
+
+    /**
+     * <p>Data bean that stores information related to a renderer.</p>
+     */
+    class RendererBean
+    {
+
+        private String componentFamily;
+
+        public String getComponentFamily()
+        {
+            return this.componentFamily;
+        }
+
+        public void setComponentFamily(String componentFamily)
+        {
+            this.componentFamily = componentFamily;
+        }
+
+        private String rendererClass;
+
+        public String getRendererClass()
+        {
+            return this.rendererClass;
+        }
+
+        public void setRendererClass(String rendererClass)
+        {
+            this.rendererClass = rendererClass;
+        }
+
+        private String rendererType;
+
+        public String getRendererType()
+        {
+            return this.rendererType;
+        }
+
+        public void setRendererType(String rendererType)
+        {
+            this.rendererType = rendererType;
+        }
+
+    }
+
+    /**
+     * <p>Digester <code>Rule</code> for processing renderers.</p>
+     */
+    class RendererRule extends Rule
+    {
+
+        public void begin(String namespace, String name, Attributes attributes)
+        {
+            getDigester().push(new RendererBean());
+        }
+
+        public void end(String namespace, String name)
+        {
+            RendererBean bean = (RendererBean) getDigester().pop();
+            RenderKit kit = (RenderKit) getDigester().peek();
+            Renderer renderer = null;
+            Class clazz = null;
+            try
+            {
+                clazz = classForName(bean.getRendererClass());
+                renderer = (Renderer) clazz.newInstance();
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException(
+                        "Exception while trying to instantiate"
+                                + " renderer class '" + bean.getRendererClass()
+                                + "' : " + e.getMessage());
+            }
+            kit.addRenderer(bean.getComponentFamily(), bean.getRendererType(),
+                    renderer);
+        }
+
+    }
+
+    /**
+     * <p>Data bean that stores information related to a validator.</p>
+     */
+    class ValidatorBean
+    {
+
+        private String validatorClass;
+
+        public String getValidatorClass()
+        {
+            return this.validatorClass;
+        }
+
+        public void setValidatorClass(String validatorClass)
+        {
+            this.validatorClass = validatorClass;
+        }
+
+        private String validatorId;
+
+        public String getValidatorId()
+        {
+            return this.validatorId;
+        }
+
+        public void setValidatorId(String validatorId)
+        {
+            this.validatorId = validatorId;
+        }
+
+    }
+
+    /**
+     * <p>Digester <code>Rule</code> for processing validators.</p>
+     */
+    class ValidatorRule extends Rule
+    {
+
+        public void begin(String namespace, String name, Attributes attributes)
+        {
+            getDigester().push(new ValidatorBean());
+        }
+
+        public void end(String namespace, String name)
+        {
+            ValidatorBean bean = (ValidatorBean) getDigester().pop();
+            Application application = (Application) getDigester().peek();
+            application.addValidator(bean.getValidatorId(), bean
+                    .getValidatorClass());
+        }
+
+    }
+
+    class ClientBehaviorRendererBean
+    {
+        private String clientBehaviorRendererType;
+
+        private String clientBehaviorRendererClass;
+
+        public String getClientBehaviorRendererType()
+        {
+            return clientBehaviorRendererType;
+        }
+
+        public void setClientBehaviorRendererType(
+                String clientBehaviorRendererType)
+        {
+            this.clientBehaviorRendererType = clientBehaviorRendererType;
+        }
+
+        public String getClientBehaviorRendererClass()
+        {
+            return clientBehaviorRendererClass;
+        }
+
+        public void setClientBehaviorRendererClass(
+                String clientBehaviorRendererClass)
+        {
+            this.clientBehaviorRendererClass = clientBehaviorRendererClass;
+        }
+    }
+
+    class ClientBehaviorRendererRule extends Rule
+    {
+        public void begin(String namespace, String name, Attributes attributes)
+        {
+            getDigester().push(new ClientBehaviorRendererBean());
+        }
+
+        public void end(String namespace, String name)
+        {
+            ClientBehaviorRendererBean bean = (ClientBehaviorRendererBean) getDigester()
+                    .pop();
+            RenderKit kit = (RenderKit) getDigester().peek();
+            ClientBehaviorRenderer renderer = null;
+            Class clazz = null;
+            try
+            {
+                clazz = classForName(bean.getClientBehaviorRendererClass());
+                renderer = (ClientBehaviorRenderer) clazz.newInstance();
+            }
+            catch (Exception e)
+            {
+                throw new IllegalArgumentException(
+                        "Exception while trying to instantiate"
+                                + " client behavior renderer class '"
+                                + bean.getClientBehaviorRendererClass()
+                                + "' : " + e.getMessage());
+            }
+            kit.addClientBehaviorRenderer(bean.getClientBehaviorRendererType(),
+                    renderer);
+        }
+    }
+
+    /**
+     * <p>Data bean that stores information related to a behavior.</p>
+     */
+    class BehaviorBean
+    {
+
+        private String behaviorClass;
+
+        public String getBehaviorClass()
+        {
+            return this.behaviorClass;
+        }
+
+        @SuppressWarnings("unused")
+        public void setBehaviorClass(String behaviorClass)
+        {
+            this.behaviorClass = behaviorClass;
+        }
+
+        private String behaviorId;
+
+        public String getBehaviorId()
+        {
+            return this.behaviorId;
+        }
+
+        @SuppressWarnings("unused")
+        public void setBehaviorId(String behaviorId)
+        {
+            this.behaviorId = behaviorId;
+        }
+
+    }
+
+    /**
+     * <p>Digester <code>Rule</code> for processing behaviors.</p>
+     */
+    class BehaviorRule extends Rule
+    {
+
+        public void begin(String namespace, String name, Attributes attributes)
+        {
+            getDigester().push(new BehaviorBean());
+        }
+
+        public void end(String namespace, String name)
+        {
+            BehaviorBean bean = (BehaviorBean) getDigester().pop();
+            Application application = (Application) getDigester().peek();
+            application.addBehavior(bean.getBehaviorId(), bean
+                    .getBehaviorClass());
+        }
+
+    }
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/config/ResourceBundleVarNames.java b/test/src/main/java/org/apache/myfaces/test/config/ResourceBundleVarNames.java
new file mode 100644
index 0000000..2edc340
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/config/ResourceBundleVarNames.java
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+package org.apache.myfaces.test.config;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Rudy De Busscher
+ */
+public final class ResourceBundleVarNames
+{
+
+    private static Map<String, String> varNames = new HashMap<String, String>();
+
+    private ResourceBundleVarNames()
+    {
+    }
+
+    public static void addVarName(String varName, String fullyQualifiedBaseName)
+    {
+        varNames.put(varName, fullyQualifiedBaseName);
+    }
+
+    public static String getVarName(String varName)
+    {
+        return varNames.get(varName);
+    }
+
+    public static void resetNames()
+    {
+        varNames.clear();
+    }
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/el/AbstractELResolver.java b/test/src/main/java/org/apache/myfaces/test/el/AbstractELResolver.java
new file mode 100644
index 0000000..6ec43c2
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/el/AbstractELResolver.java
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.el;
+
+import java.beans.FeatureDescriptor;
+import javax.el.ELResolver;
+
+/**
+ * <p>Convenience base class for EL resolvers.</p>
+ * 
+ * @since 1.0.0
+ */
+abstract class AbstractELResolver extends ELResolver
+{
+
+    // ------------------------------------------------------- Protected Methods
+
+    /**
+     * <p>Create and return a <code>FeatureDescriptor</code> configured with
+     * the specified arguments.</p>
+     *
+     * @param name Feature name
+     * @param displayName Display name
+     * @param description Short description
+     * @param expert Flag indicating this feature is for experts
+     * @param hidden Flag indicating this feature should be hidden
+     * @param preferred Flag indicating this feature is the preferred one
+     *  among features of the same type
+     * @param type Runtime type of this feature
+     * @param designTime Flag indicating feature is resolvable at design time
+     */
+    protected FeatureDescriptor descriptor(String name, String displayName,
+            String description, boolean expert, boolean hidden,
+            boolean preferred, Object type, boolean designTime)
+    {
+
+        FeatureDescriptor descriptor = new FeatureDescriptor();
+
+        descriptor.setName(name);
+        descriptor.setDisplayName(displayName);
+        descriptor.setShortDescription(description);
+        descriptor.setExpert(expert);
+        descriptor.setHidden(hidden);
+        descriptor.setPreferred(preferred);
+        descriptor.setValue(ELResolver.TYPE, type);
+        if (designTime)
+        {
+            descriptor.setValue(ELResolver.RESOLVABLE_AT_DESIGN_TIME,
+                    Boolean.TRUE);
+        }
+        else
+        {
+            descriptor.setValue(ELResolver.RESOLVABLE_AT_DESIGN_TIME,
+                    Boolean.FALSE);
+        }
+
+        return descriptor;
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/el/ExpressionTokenizer.java b/test/src/main/java/org/apache/myfaces/test/el/ExpressionTokenizer.java
new file mode 100644
index 0000000..6798cec
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/el/ExpressionTokenizer.java
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+package org.apache.myfaces.test.el;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.text.ParsePosition;
+import java.util.ArrayList;
+
+/**
+ * Expression Tokenizer
+ */
+class ExpressionTokenizer
+{
+    private ExpressionTokenizer()
+    {
+    }
+
+    public static String[] tokenize(CharSequence expr)
+    {
+        final ArrayList<String> tokens = new ArrayList<String>();
+        ParsePosition pos = new ParsePosition(0);
+        int len = expr.length();
+        boolean sep = true;
+        while (pos.getIndex() < len)
+        {
+            int here = pos.getIndex();
+            char c = expr.charAt(here);
+            switch (c)
+            {
+            case ' ':
+                next(pos);
+                break;
+            case ']':
+                throw new IllegalStateException(String.format("Position %s: unexpected '%s'", here, c));
+            case '[':
+                tokens.add(parseIndex(expr, next(pos)));
+                break;
+            case '.':
+                if (sep)
+                {
+                    throw new IllegalStateException(String.format(
+                        "Position %s: expected property, index/key, or end of expression", here));
+                }
+                sep = true;
+                next(pos);
+                // fall through:
+            default:
+                if (!sep)
+                {
+                    throw new IllegalStateException(String.format(
+                        "Position %s: expected property path separator, index/key, or end of expression", here));
+                }
+                tokens.add(parseProperty(expr, pos));
+            }
+            sep = false;
+        }
+        return tokens.toArray(new String[tokens.size()]);
+    }
+
+    private static ParsePosition next(ParsePosition pos)
+    {
+        pos.setIndex(pos.getIndex() + 1);
+        return pos;
+    }
+
+    private static String parseProperty(CharSequence expr, ParsePosition pos)
+    {
+        int len = expr.length();
+        int start = pos.getIndex();
+        loop: while (pos.getIndex() < len)
+        {
+            switch (expr.charAt(pos.getIndex()))
+            {
+            case '[':
+            case ']':
+            case '.':
+                break loop;
+            default:
+            }
+            next(pos);
+        }
+        if (pos.getIndex() > start)
+        {
+            return expr.subSequence(start, pos.getIndex()).toString();
+        }
+        throw new IllegalStateException(String.format("Position %s: expected property", start));
+    }
+
+    /**
+     * Handles an index/key. If the text contained between [] is surrounded by a
+     * pair of " or ', these will be stripped.
+     * 
+     * @param expr Expression string to tokenize
+     * @param pos current position of parser, will be updated by the method.
+     * @return token found on the position
+     */
+    private static String parseIndex(CharSequence expr, ParsePosition pos)
+    {
+        int len = expr.length();
+        int start = pos.getIndex();
+        if (start < len)
+        {
+            char first = expr.charAt(pos.getIndex());
+            if (first == '"' || first == '\'')
+            {
+                String s = parseQuotedString(expr, pos);
+                if (s != null && expr.charAt(pos.getIndex()) == ']')
+                {
+                    next(pos);
+                    return s;
+                }
+            }
+            // no quoted string; match ] greedily and trim
+            while (pos.getIndex() < len)
+            {
+                int here = pos.getIndex();
+                try
+                {
+                    if (expr.charAt(here) == ']')
+                    {
+                        return expr.subSequence(start, here).toString().trim();
+                    }
+                }
+                finally
+                {
+                    next(pos);
+                }
+            }
+        }
+        throw new IllegalStateException(String.format("Position %s: unparsable index", start));
+    }
+
+    private static String parseQuotedString(CharSequence expr, ParsePosition pos)
+    {
+        int len = expr.length();
+        int start = pos.getIndex();
+        if (start < len)
+        {
+            char quote = expr.charAt(start);
+            next(pos);
+            StringWriter w = new StringWriter();
+            while (pos.getIndex() < len)
+            {
+                int here = pos.getIndex();
+                char c = expr.charAt(here);
+                boolean esc = false;
+                if (c == '\\' && here + 1 < len && expr.charAt(here + 1) == quote)
+                {
+                    esc = true;
+                    here = next(pos).getIndex();
+                }
+                try
+                {
+                    // look for matching quote
+                    if (c == quote && !esc)
+                    {
+                        return w.toString();
+                    }
+                    w.write(Character.toChars(Character.codePointAt(expr, here)));
+                }
+                catch (IOException e)
+                {
+                    throw new RuntimeException(e);
+                }
+                finally
+                {
+                    next(pos);
+                }
+            }
+            // if reached, reset due to no ending quote found
+            pos.setIndex(start);
+        }
+        return null;
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/el/FacesImplicitObjectELResolver.java b/test/src/main/java/org/apache/myfaces/test/el/FacesImplicitObjectELResolver.java
new file mode 100644
index 0000000..94e7155
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/el/FacesImplicitObjectELResolver.java
@@ -0,0 +1,317 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.el;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.el.ELContext;
+import javax.el.PropertyNotFoundException;
+import javax.el.PropertyNotWritableException;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+
+/**
+ * <p><code>ELResolver</code> implementation that accesses implicit objects
+ * in the current request context.  See the JSF 1.2 Specification, section
+ * 5.6.2.1, for requirements implemented by this class.</p>
+ *
+ * @since 1.0.0
+ */
+public class FacesImplicitObjectELResolver extends AbstractELResolver
+{
+
+    /**
+     * <p>The names of all implicit objects recognized by this resolver.</p>
+     */
+    private static final String[] NAMES = { "application", "applicationScope",
+            "cookie", "facesContext", "header", "headerValues", "initParam",
+            "param", "paramValues", "request", "requestScope", "session",
+            "sessionScope", "view" };
+
+    /**
+     * <p>The property types corresponding to the implicit object names.</p>
+     */
+    private static final Class[] TYPES = { Object.class, Map.class, Map.class,
+            FacesContext.class, Map.class, Map.class, Map.class, Map.class,
+            Map.class, Object.class, Map.class, Object.class, Map.class,
+            UIViewRoot.class };
+
+    /**
+     * <p>The settable value types corresponding to the implicit
+     * object names.</p>
+     */
+    private static final Class[] VALUES = { null, Object.class, null, null,
+            null, null, null, null, null, null, Object.class, null,
+            Object.class, null };
+
+    /**
+     * <p>Return the most general type this resolver accepts for the
+     * <code>property</code> argument.</p>
+     */
+    public Class getCommonPropertyType(ELContext context, Object base)
+    {
+
+        if (base != null)
+        {
+            return null;
+        }
+        else
+        {
+            return String.class;
+        }
+
+    }
+
+    /**
+     * <p>Return an <code>Iterator</code> over the attributes that this
+     * resolver knows how to deal with.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     */
+    public Iterator getFeatureDescriptors(ELContext context, Object base)
+    {
+
+        if (base != null)
+        {
+            return null;
+        }
+
+        // Create the variables we will need
+        FacesContext fcontext = (FacesContext) context
+                .getContext(FacesContext.class);
+        List descriptors = new ArrayList();
+
+        // Add feature descriptors for each implicit object
+        for (int i = 0; i < NAMES.length; i++)
+        {
+            descriptors.add(descriptor(NAMES[i], NAMES[i], NAMES[i], false,
+                    false, true, TYPES[i], true));
+        }
+
+        // Return the accumulated descriptors
+        return descriptors.iterator();
+
+    }
+
+    /**
+     * <p>Return the Java type of the specified property.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     */
+    public Class getType(ELContext context, Object base, Object property)
+    {
+
+        if (base != null)
+        {
+            return null;
+        }
+        if (property == null)
+        {
+            throw new PropertyNotFoundException("No property specified");
+        }
+        String name = property.toString();
+        for (int i = 0; i < NAMES.length; i++)
+        {
+            if (name.equals(NAMES[i]))
+            {
+                context.setPropertyResolved(true);
+                return VALUES[i];
+            }
+        }
+        return null;
+
+    }
+
+    /**
+     * <p>Return an existing scoped object for the specified name (if any);
+     * otherwise, return <code>null</code>.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     */
+    public Object getValue(ELContext context, Object base, Object property)
+    {
+
+        if (base != null)
+        {
+            return null;
+        }
+        if (property == null)
+        {
+            throw new PropertyNotFoundException("No property specified");
+        }
+
+        FacesContext fcontext = (FacesContext) context
+                .getContext(FacesContext.class);
+        ExternalContext econtext = fcontext.getExternalContext();
+        String name = property.toString();
+
+        if (name.equals("application"))
+        {
+            context.setPropertyResolved(true);
+            return econtext.getContext();
+        }
+        else if (name.equals("applicationScope"))
+        {
+            context.setPropertyResolved(true);
+            return econtext.getApplicationMap();
+        }
+        else if (name.equals("cookie"))
+        {
+            context.setPropertyResolved(true);
+            return econtext.getRequestCookieMap();
+        }
+        else if (name.equals("facesContext"))
+        {
+            context.setPropertyResolved(true);
+            return fcontext;
+        }
+        else if (name.equals("header"))
+        {
+            context.setPropertyResolved(true);
+            return econtext.getRequestHeaderMap();
+        }
+        else if (name.equals("headerValues"))
+        {
+            context.setPropertyResolved(true);
+            return econtext.getRequestHeaderValuesMap();
+        }
+        else if (name.equals("initParam"))
+        {
+            context.setPropertyResolved(true);
+            return econtext.getInitParameterMap();
+        }
+        else if (name.equals("param"))
+        {
+            context.setPropertyResolved(true);
+            return econtext.getRequestParameterMap();
+        }
+        else if (name.equals("paramValues"))
+        {
+            context.setPropertyResolved(true);
+            return econtext.getRequestParameterValuesMap();
+        }
+        else if (name.equals("request"))
+        {
+            context.setPropertyResolved(true);
+            return econtext.getRequest();
+        }
+        else if (name.equals("requestScope"))
+        {
+            context.setPropertyResolved(true);
+            return econtext.getRequestMap();
+        }
+        else if (name.equals("session"))
+        {
+            context.setPropertyResolved(true);
+            return econtext.getSession(true);
+        }
+        else if (name.equals("sessionScope"))
+        {
+            context.setPropertyResolved(true);
+            return econtext.getSessionMap();
+        }
+        else if (name.equals("view"))
+        {
+            context.setPropertyResolved(true);
+            return fcontext.getViewRoot();
+        }
+
+        return null;
+
+    }
+
+    /**
+     * <p>Return <code>true</code> if the specified property is read only.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     */
+    public boolean isReadOnly(ELContext context, Object base, Object property)
+    {
+
+        if (base != null)
+        {
+            return false;
+        }
+        if (property == null)
+        {
+            throw new PropertyNotFoundException("No property specified");
+        }
+        String name = property.toString();
+        for (int i = 0; i < NAMES.length; i++)
+        {
+            if (name.equals(NAMES[i]))
+            {
+                context.setPropertyResolved(true);
+                return true;
+            }
+        }
+        return false;
+
+    }
+
+    /**
+     * <p>Set the value of a scoped object for the specified name.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     * @param value New value to be set
+     */
+    public void setValue(ELContext context, Object base, Object property,
+            Object value)
+    {
+
+        if (base != null)
+        {
+            return;
+        }
+        if (property == null)
+        {
+            throw new PropertyNotFoundException("No property specified");
+        }
+
+        String name = property.toString();
+        for (int i = 0; i < NAMES.length; i++)
+        {
+            if (name.equals(NAMES[i]))
+            {
+                context.setPropertyResolved(true);
+                throw new PropertyNotWritableException(name);
+            }
+        }
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/el/FacesResourceBundleELResolver.java b/test/src/main/java/org/apache/myfaces/test/el/FacesResourceBundleELResolver.java
new file mode 100644
index 0000000..e7adb25
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/el/FacesResourceBundleELResolver.java
@@ -0,0 +1,236 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.el;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ResourceBundle;
+import java.util.Map.Entry;
+
+import javax.el.ELContext;
+import javax.el.PropertyNotFoundException;
+import javax.el.PropertyNotWritableException;
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.test.mock.MockApplication12;
+
+/**
+ * <p><code>ELResolver</code> implementation that accesses resource bundles
+ * in the current application.  See the JSF 1.2 Specification, section
+ * 5.6.1.3, for requirements implemented by this class.</p>
+ *
+ * @since 1.0.0
+ */
+public class FacesResourceBundleELResolver extends AbstractELResolver
+{
+
+    /**
+     * <p>Return the most general type this resolver accepts for the
+     * <code>property</code> argument.</p>
+     */
+    public Class getCommonPropertyType(ELContext context, Object base)
+    {
+
+        if (base != null)
+        {
+            return null;
+        }
+        else
+        {
+            return String.class;
+        }
+
+    }
+
+    /**
+     * <p>Return an <code>Iterator</code> over the attributes that this
+     * resolver knows how to deal with.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     */
+    public Iterator getFeatureDescriptors(ELContext context, Object base)
+    {
+
+        if (base != null)
+        {
+            return null;
+        }
+
+        // Create the variables we will need
+        List descriptors = new ArrayList();
+        FacesContext fcontext = (FacesContext) context
+                .getContext(FacesContext.class);
+        MockApplication12 application = (MockApplication12) fcontext
+                .getApplication();
+        String key = null;
+        Object value = null;
+
+        // Create a feature descriptor for each configured resource bundle
+        Iterator entries = application.getResourceBundles().entrySet()
+                .iterator();
+        while (entries.hasNext())
+        {
+            Entry entry = (Entry) entries.next();
+            key = (String) entry.getKey();
+            value = entry.getValue();
+            descriptors.add(descriptor(key, key, "Resource Bundle " + key,
+                    false, false, true, ResourceBundle.class, true));
+        }
+
+        // Return the accumulated descriptors
+        return descriptors.iterator();
+
+    }
+
+    /**
+     * <p>Return the Java type of the specified property.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     */
+    public Class getType(ELContext context, Object base, Object property)
+    {
+
+        if (base != null)
+        {
+            return null;
+        }
+        if (property == null)
+        {
+            throw new PropertyNotFoundException("No property specified");
+        }
+        FacesContext fcontext = (FacesContext) context
+                .getContext(FacesContext.class);
+        ResourceBundle bundle = fcontext.getApplication().getResourceBundle(
+                fcontext, property.toString());
+        if (bundle != null)
+        {
+            context.setPropertyResolved(true);
+            return ResourceBundle.class;
+        }
+        return null;
+
+    }
+
+    /**
+     * <p>Return a resource bundle for the specified name (if any);
+     * otherwise, return <code>null</code>.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     */
+    public Object getValue(ELContext context, Object base, Object property)
+    {
+
+        if (base != null)
+        {
+            return null;
+        }
+        if (property == null)
+        {
+            throw new PropertyNotFoundException("No property specified");
+        }
+
+        FacesContext fcontext = (FacesContext) context
+                .getContext(FacesContext.class);
+        ResourceBundle bundle = fcontext.getApplication().getResourceBundle(
+                fcontext, property.toString());
+        if (bundle != null)
+        {
+            context.setPropertyResolved(true);
+            return bundle;
+        }
+        return null;
+
+    }
+
+    /**
+     * <p>Return <code>true</code> if the specified property is read only.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     */
+    public boolean isReadOnly(ELContext context, Object base, Object property)
+    {
+
+        if (base != null)
+        {
+            return false;
+        }
+        if (property == null)
+        {
+            throw new PropertyNotFoundException("No property specified");
+        }
+        FacesContext fcontext = (FacesContext) context
+                .getContext(FacesContext.class);
+        ResourceBundle bundle = fcontext.getApplication().getResourceBundle(
+                fcontext, property.toString());
+        if (bundle != null)
+        {
+            context.setPropertyResolved(true);
+            return true;
+        }
+        return false;
+
+    }
+
+    /**
+     * <p>Set the value of a scoped object for the specified name.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     * @param value New value to be set
+     */
+    public void setValue(ELContext context, Object base, Object property,
+            Object value)
+    {
+
+        if (base != null)
+        {
+            return;
+        }
+        if (property == null)
+        {
+            throw new PropertyNotFoundException("No property specified");
+        }
+
+        FacesContext fcontext = (FacesContext) context
+                .getContext(FacesContext.class);
+        ResourceBundle bundle = fcontext.getApplication().getResourceBundle(
+                fcontext, property.toString());
+        if (bundle != null)
+        {
+            context.setPropertyResolved(true);
+            throw new PropertyNotWritableException(property.toString());
+        }
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/el/FacesScopedAttributeELResolver.java b/test/src/main/java/org/apache/myfaces/test/el/FacesScopedAttributeELResolver.java
new file mode 100644
index 0000000..bd2e6df
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/el/FacesScopedAttributeELResolver.java
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.el;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import javax.el.ELContext;
+import javax.el.PropertyNotFoundException;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+
+/**
+ * <p><code>ELResolver</code> implementation that accesses scoped variables
+ * in the current request context.  See the JSF 1.2 Specification, section
+ * 5.6.2.7, for requirements implemented by this class.</p>
+ *
+ * @since 1.0.0
+ */
+public class FacesScopedAttributeELResolver extends AbstractELResolver
+{
+
+    /**
+     * <p>Return the most general type this resolver accepts for the
+     * <code>property</code> argument.</p>
+     */
+    public Class getCommonPropertyType(ELContext context, Object base)
+    {
+
+        if (base != null)
+        {
+            return null;
+        }
+        else
+        {
+            return String.class;
+        }
+
+    }
+
+    /**
+     * <p>Return an <code>Iterator</code> over the attributes that this
+     * resolver knows how to deal with.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     */
+    public Iterator getFeatureDescriptors(ELContext context, Object base)
+    {
+
+        if (base != null)
+        {
+            return null;
+        }
+
+        // Create the variables we will need
+        FacesContext fcontext = (FacesContext) context
+                .getContext(FacesContext.class);
+        ExternalContext econtext = fcontext.getExternalContext();
+        List descriptors = new ArrayList();
+        Map map = null;
+        Set set = null;
+        Iterator items = null;
+        String key = null;
+        Object value = null;
+
+        // Add feature descriptors for request scoped attributes
+        set = econtext.getRequestMap().entrySet();
+        items = set.iterator();
+        while (items.hasNext())
+        {
+            Entry item = (Entry) items.next();
+            key = (String) item.getKey();
+            value = item.getValue();
+            descriptors.add(descriptor(key, key, "Request Scope Attribute "
+                    + key, false, false, true, value.getClass(), true));
+        }
+
+        // Add feature descriptors for session scoped attributes
+        set = econtext.getSessionMap().entrySet();
+        items = set.iterator();
+        while (items.hasNext())
+        {
+            Entry item = (Entry) items.next();
+            key = (String) item.getKey();
+            value = item.getValue();
+            descriptors.add(descriptor(key, key, "Session Scope Attribute "
+                    + key, false, false, true, value.getClass(), true));
+        }
+
+        // Add feature descriptors for application scoped attributes
+        set = econtext.getApplicationMap().entrySet();
+        items = set.iterator();
+        while (items.hasNext())
+        {
+            Entry item = (Entry) items.next();
+            key = (String) item.getKey();
+            value = item.getValue();
+            descriptors.add(descriptor(key, key, "Application Scope Attribute "
+                    + key, false, false, true, value.getClass(), true));
+        }
+
+        // Return the accumulated descriptors
+        return descriptors.iterator();
+
+    }
+
+    /**
+     * <p>Return the Java type of the specified property.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     */
+    public Class getType(ELContext context, Object base, Object property)
+    {
+
+        if (base != null)
+        {
+            return null;
+        }
+        if (property == null)
+        {
+            throw new PropertyNotFoundException("No property specified");
+        }
+        context.setPropertyResolved(true);
+        return Object.class;
+
+    }
+
+    /**
+     * <p>Return an existing scoped object for the specified name (if any);
+     * otherwise, return <code>null</code>.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     */
+    public Object getValue(ELContext context, Object base, Object property)
+    {
+
+        if (base != null)
+        {
+            return null;
+        }
+        if (property == null)
+        {
+            throw new PropertyNotFoundException("No property specified");
+        }
+
+        FacesContext fcontext = (FacesContext) context
+                .getContext(FacesContext.class);
+        ExternalContext econtext = fcontext.getExternalContext();
+        Object value = null;
+        value = econtext.getRequestMap().get(property);
+        if (value != null)
+        {
+            context.setPropertyResolved(true);
+            return value;
+        }
+        value = econtext.getSessionMap().get(property);
+        if (value != null)
+        {
+            context.setPropertyResolved(true);
+            return value;
+        }
+        value = econtext.getApplicationMap().get(property);
+        if (value != null)
+        {
+            context.setPropertyResolved(true);
+            return value;
+        }
+
+        return null;
+
+    }
+
+    /**
+     * <p>Return <code>true</code> if the specified property is read only.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     */
+    public boolean isReadOnly(ELContext context, Object base, Object property)
+    {
+
+        if (base == null)
+        {
+            context.setPropertyResolved(true);
+            return false;
+        }
+        return false;
+
+    }
+
+    /**
+     * <p>Set the value of a scoped object for the specified name.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     * @param value New value to be set
+     */
+    public void setValue(ELContext context, Object base, Object property,
+            Object value)
+    {
+
+        if (base != null)
+        {
+            return;
+        }
+        if (property == null)
+        {
+            throw new PropertyNotFoundException("No property specified");
+        }
+
+        context.setPropertyResolved(true);
+        String key = property.toString();
+        Object result = null;
+        FacesContext fcontext = (FacesContext) context
+                .getContext(FacesContext.class);
+        ExternalContext econtext = fcontext.getExternalContext();
+
+        if (econtext.getRequestMap().containsKey(property))
+        {
+            econtext.getRequestMap().put(key, value);
+        }
+        else if (econtext.getSessionMap().containsKey(property))
+        {
+            econtext.getSessionMap().put(key, value);
+        }
+        else if (econtext.getApplicationMap().containsKey(property))
+        {
+            econtext.getApplicationMap().put(key, value);
+        }
+        else
+        {
+            econtext.getRequestMap().put(key, value);
+        }
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/el/FacesVariableResolverChainWrapper.java b/test/src/main/java/org/apache/myfaces/test/el/FacesVariableResolverChainWrapper.java
new file mode 100644
index 0000000..e3b89de
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/el/FacesVariableResolverChainWrapper.java
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.el;
+
+import java.util.Iterator;
+
+import javax.el.ELContext;
+import javax.el.PropertyNotFoundException;
+import javax.faces.FacesException;
+
+/**
+ * <p><code>ELResolver</code> implementation that wraps the legacy (JSF 1.1)
+ * <code>VariableResolver</code> chain.  See the JSF 1.2 Specification, section
+ * 5.6.1.5, for requirements implemented by this class.</p>
+ *
+ * @since 1.0.0
+ */
+public class FacesVariableResolverChainWrapper extends AbstractELResolver
+{
+
+    /**
+     * <p>Return the most general type this resolver accepts for the
+     * <code>property</code> argument.</p>
+     */
+    public Class getCommonPropertyType(ELContext context, Object base)
+    {
+
+        if (base != null)
+        {
+            return null;
+        }
+        else
+        {
+            return String.class;
+        }
+
+    }
+
+    /**
+     * <p>Return an <code>Iterator</code> over the attributes that this
+     * resolver knows how to deal with.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     */
+    public Iterator getFeatureDescriptors(ELContext context, Object base)
+    {
+
+        return null;
+
+    }
+
+    /**
+     * <p>Return the Java type of the specified property.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     */
+    public Class getType(ELContext context, Object base, Object property)
+    {
+
+        if ((base == null) && (property == null))
+        {
+            throw new PropertyNotFoundException("No property specified");
+        }
+        return null;
+
+    }
+
+    /**
+     * <p>Evaluate with the legacy variable resolver chain and return
+     * the value.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     */
+    public Object getValue(ELContext context, Object base, Object property)
+    {
+        throw new FacesException("not supported anymore");
+
+    }
+
+    /**
+     * <p>Return <code>true</code> if the specified property is read only.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     */
+    public boolean isReadOnly(ELContext context, Object base, Object property)
+    {
+
+        if ((base == null) && (property == null))
+        {
+            throw new PropertyNotFoundException("No property specified");
+        }
+        return false;
+
+    }
+
+    /**
+     * <p>Set the value of a scoped object for the specified name.</p>
+     *
+     * @param context <code>ELContext</code> for evaluating this value
+     * @param base Base object against which this evaluation occurs
+     *  (must be null because we are evaluating a top level variable)
+     * @param property Property name to be accessed
+     * @param value New value to be set
+     */
+    public void setValue(ELContext context, Object base, Object property,
+            Object value)
+    {
+
+        if ((base == null) && (property == null))
+        {
+            throw new PropertyNotFoundException("No property specified");
+        }
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/el/MockCompositeValueExpression.java b/test/src/main/java/org/apache/myfaces/test/el/MockCompositeValueExpression.java
new file mode 100644
index 0000000..ce77bab
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/el/MockCompositeValueExpression.java
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.el;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.el.ELContext;
+import javax.el.ValueExpression;
+
+/**
+ * A value expression implementation that is capable of handling composite expressions.
+ * It handles composites expressions but creating a list of 'simple' expressions which 
+ * are 'pure', only literal text or only references like #{}
+ * 
+ * @author Rudy De Busscher
+ * @since 1.0.0
+ */
+public class MockCompositeValueExpression extends MockValueExpression
+{
+
+    private static final long serialVersionUID = 2645070462654392076L;
+
+    private List<ValueExpression> valueExpressionChain;
+
+    public MockCompositeValueExpression(String expression, Class expectedType)
+    {
+
+        super("#{}", expectedType);
+        buildExpressionChain(expression, expectedType);
+
+    }
+
+    private void buildExpressionChain(String expression, Class expectedType)
+    {
+        valueExpressionChain = new ArrayList<ValueExpression>();
+        StringBuilder parser = new StringBuilder(expression);
+        int pos = getStartPositionOfReference(parser);
+        while (pos > -1 || parser.length() > 0)
+        {
+            // We have a constant first
+            if (pos > 0)
+            {
+                valueExpressionChain.add(new MockValueExpression(parser
+                        .substring(0, pos), expectedType));
+                parser.delete(0, pos);
+            }
+            // We have an el, maybe literal at the end
+            if (pos == 0)
+            {
+                int posBracket = parser.indexOf("}");
+                valueExpressionChain.add(new MockValueExpression(parser
+                        .substring(0, posBracket + 1), expectedType));
+
+                parser.delete(0, posBracket + 1);
+            }
+            // Only literal
+            if (pos == -1)
+            {
+                valueExpressionChain.add(new MockValueExpression(parser
+                        .toString(), expectedType));
+
+                parser.setLength(0);
+            }
+            pos = getStartPositionOfReference(parser);
+        }
+    }
+
+    @Override
+    public Class getType(ELContext context)
+    {
+        switch (valueExpressionChain.size())
+        {
+        case 0:
+            return null;
+        case 1:
+            return valueExpressionChain.get(0).getType(context);
+        default:
+            return String.class;
+        }
+    }
+
+    @Override
+    public Object getValue(ELContext context)
+    {
+        if (valueExpressionChain.size() > 1)
+        {
+            // Well only composite strings are supported.
+
+            StringBuilder result = new StringBuilder();
+            for (ValueExpression valueExpression : valueExpressionChain)
+            {
+                result.append(valueExpression.getValue(context));
+            }
+            return result.toString();
+        }
+        else
+        {
+            if (valueExpressionChain.size() == 1)
+            {
+                return valueExpressionChain.get(0).getValue(context);
+            }
+            else
+            {
+                return null;
+            }
+        }
+    }
+
+    @Override
+    public void setValue(ELContext context, Object value)
+    {
+        if (!isReadOnly(context))
+        {
+            valueExpressionChain.get(0).setValue(context, value);
+        }
+        else
+        {
+            throw new IllegalArgumentException(
+                    "We can only set value on NON composite expressions like #{foo}");
+        }
+    }
+
+    @Override
+    public String getExpressionString()
+    {
+        StringBuilder result = new StringBuilder();
+        for (ValueExpression valueExpression : valueExpressionChain)
+        {
+            result.append(valueExpression.getExpressionString());
+        }
+        return result.toString();
+    }
+
+    @Override
+    public boolean isReadOnly(ELContext context)
+    {
+        return valueExpressionChain.size() > 1;
+    }
+
+    public static int getStartPositionOfReference(StringBuilder expressionPart)
+    {
+        int result;
+        int pos1 = expressionPart.indexOf("#{");
+        int pos2 = expressionPart.indexOf("${");
+
+        if (pos1 == -1)
+        {
+            result = pos1;
+        }
+        else if (pos2 == -1)
+        {
+            result = pos1;
+        }
+        else
+        {
+            result = Math.min(pos1, pos2);
+        }
+        return result;
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/el/MockELContext.java b/test/src/main/java/org/apache/myfaces/test/el/MockELContext.java
new file mode 100644
index 0000000..2b2130f
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/el/MockELContext.java
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.el;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import javax.el.ELContext;
+import javax.el.ELResolver;
+import javax.el.FunctionMapper;
+import javax.el.VariableMapper;
+import javax.faces.context.FacesContext;
+
+/**
+ * <p>Mock implementation of <code>ELContext</code>.</p>
+ *
+ * @since 1.0.0
+ */
+
+public class MockELContext extends ELContext
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /** Creates a new instance of MockELContext */
+    public MockELContext()
+    {
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    private Map contexts = new HashMap();
+    private FunctionMapper functionMapper = new MockFunctionMapper();
+    private Locale locale = Locale.getDefault();
+    private boolean propertyResolved;
+    private VariableMapper variableMapper = new MockVariableMapper();
+
+    // ----------------------------------------------------- Mock Object Methods
+
+    // ------------------------------------------------------- ELContext Methods
+
+    /** {@inheritDoc} */
+    public Object getContext(Class key)
+    {
+        if (key == null)
+        {
+            throw new NullPointerException();
+        }
+        return contexts.get(key);
+    }
+
+    /** {@inheritDoc} */
+    public ELResolver getELResolver()
+    {
+        FacesContext context = FacesContext.getCurrentInstance();
+        return context.getApplication().getELResolver();
+    }
+
+    /** {@inheritDoc} */
+    public FunctionMapper getFunctionMapper()
+    {
+        return this.functionMapper;
+    }
+
+    /** {@inheritDoc} */
+    public Locale getLocale()
+    {
+        return this.locale;
+    }
+
+    /** {@inheritDoc} */
+    public boolean isPropertyResolved()
+    {
+        return this.propertyResolved;
+    }
+
+    /** {@inheritDoc} */
+    public void putContext(Class key, Object value)
+    {
+        if ((key == null) || (value == null))
+        {
+            throw new NullPointerException();
+        }
+        contexts.put(key, value);
+    }
+
+    /** {@inheritDoc} */
+    public void setPropertyResolved(boolean propertyResolved)
+    {
+        this.propertyResolved = propertyResolved;
+    }
+
+    /** {@inheritDoc} */
+    public VariableMapper getVariableMapper()
+    {
+        return this.variableMapper;
+    }
+
+    /** {@inheritDoc} */
+    public void setLocale(Locale locale)
+    {
+        this.locale = locale;
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/el/MockExpressionFactory.java b/test/src/main/java/org/apache/myfaces/test/el/MockExpressionFactory.java
new file mode 100644
index 0000000..34e5c74
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/el/MockExpressionFactory.java
@@ -0,0 +1,365 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.el;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import javax.el.ELContext;
+import javax.el.ExpressionFactory;
+import javax.el.MethodExpression;
+import javax.el.ValueExpression;
+
+/**
+ * <p>Mock implementation of <code>ExpressionFactory</code>.</p>
+ *
+ * @since 1.0.0
+ */
+public class MockExpressionFactory extends ExpressionFactory
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /** Creates a new instance of MockExpressionFactory */
+    public MockExpressionFactory()
+    {
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>Literal numeric value for zero.</p>
+     */
+    private static final Integer ZERO = new Integer(0);
+
+    // ----------------------------------------------------- Mock Object Methods
+
+    // ----------------------------------------------- ExpressionFactory Methods
+
+    /** {@inheritDoc} */
+    public Object coerceToType(Object object, Class targetType)
+    {
+
+        // Check for no conversion necessary
+        if ((targetType == null) || Object.class.equals(targetType))
+        {
+            return object;
+        }
+
+        // Coerce to String if appropriate
+        if (String.class.equals(targetType))
+        {
+            if (object == null)
+            {
+                return "";
+            }
+            else if (object instanceof String)
+            {
+                return (String) object;
+            }
+            else
+            {
+                return object.toString();
+            }
+        }
+
+        // Coerce to Number (or a subclass of Number) if appropriate
+        if (isNumeric(targetType))
+        {
+            if (object == null)
+            {
+                return coerce(ZERO, targetType);
+            }
+            else if ("".equals(object))
+            {
+                return coerce(ZERO, targetType);
+            }
+            else if (object instanceof String)
+            {
+                return coerce((String) object, targetType);
+            }
+            else if (isNumeric(object.getClass()))
+            {
+                return coerce((Number) object, targetType);
+            }
+            throw new IllegalArgumentException("Cannot convert " + object
+                    + " to Number");
+        }
+
+        // Coerce to Boolean if appropriate
+        if (Boolean.class.equals(targetType) || (Boolean.TYPE == targetType))
+        {
+            if (object == null)
+            {
+                return Boolean.FALSE;
+            }
+            else if ("".equals(object))
+            {
+                return Boolean.FALSE;
+            }
+            else if ((object instanceof Boolean)
+                    || (object.getClass() == Boolean.TYPE))
+            {
+                return (Boolean) object;
+            }
+            else if (object instanceof String)
+            {
+                return Boolean.valueOf((String) object);
+            }
+            throw new IllegalArgumentException("Cannot convert " + object
+                    + " to Boolean");
+        }
+
+        // Coerce to Character if appropriate
+        if (Character.class.equals(targetType)
+                || (Character.TYPE == targetType))
+        {
+            if (object == null)
+            {
+                return new Character((char) 0);
+            }
+            else if ("".equals(object))
+            {
+                return new Character((char) 0);
+            }
+            else if (object instanceof String)
+            {
+                return new Character(((String) object).charAt(0));
+            }
+            else if (isNumeric(object.getClass()))
+            {
+                return new Character((char) ((Number) object).shortValue());
+            }
+            else if ((object instanceof Character)
+                    || (object.getClass() == Character.TYPE))
+            {
+                return (Character) object;
+            }
+            throw new IllegalArgumentException("Cannot convert " + object
+                    + " to Character");
+        }
+        
+        if (targetType.isEnum())
+        {
+            if (object == null || "".equals(object))
+            {
+                return null;
+            }
+            if (targetType.isAssignableFrom(object.getClass()))
+            {
+                return (Enum) object;
+            }
+            
+            if (!(object instanceof String))
+            {
+                throw new IllegalArgumentException("Cannot convert " + object + " to Enum");
+            }
+
+            Enum<?> result;
+            try
+            {
+                 result = Enum.valueOf(targetType, (String) object);
+                 return result;
+            }
+            catch (IllegalArgumentException iae)
+            {
+                throw new IllegalArgumentException("Cannot convert " + object + " to Enum");
+            }
+        }
+
+        // Is the specified value type-compatible already?
+        if ((object != null) && targetType.isAssignableFrom(object.getClass()))
+        {
+            return object;
+        }
+
+        // new to spec
+        if (object == null)
+        {
+            return null;
+        }
+
+        // We do not know how to perform this conversion
+        throw new IllegalArgumentException("Cannot convert " + object + " to "
+                + targetType.getName());
+
+    }
+
+    /** {@inheritDoc} */
+    public MethodExpression createMethodExpression(ELContext context,
+            String expression, Class expectedType, Class[] signature)
+    {
+
+        return new MockMethodExpression(expression, signature, expectedType);
+
+    }
+
+    /** {@inheritDoc} */
+    public ValueExpression createValueExpression(ELContext context,
+            String expression, Class expectedType)
+    {
+
+        return new MockCompositeValueExpression(expression, expectedType);
+
+    }
+
+    /** {@inheritDoc} */
+    public ValueExpression createValueExpression(Object instance,
+            Class expectedType)
+    {
+
+        return new MockVariableValueExpression(instance, expectedType);
+
+    }
+
+    // --------------------------------------------------------- Private Methods
+
+    /**
+     * <p>Coerce the specified value to the specified Number subclass.</p>
+     *
+     * @param value Value to be coerced
+     * @param type Destination type
+     */
+    private Number coerce(Number value, Class type)
+    {
+
+        if ((type == Byte.TYPE) || (type == Byte.class))
+        {
+            return new Byte(value.byteValue());
+        }
+        else if ((type == Double.TYPE) || (type == Double.class))
+        {
+            return new Double(value.doubleValue());
+        }
+        else if ((type == Float.TYPE) || (type == Float.class))
+        {
+            return new Float(value.floatValue());
+        }
+        else if ((type == Integer.TYPE) || (type == Integer.class))
+        {
+            return new Integer(value.intValue());
+        }
+        else if ((type == Long.TYPE) || (type == Long.class))
+        {
+            return new Long(value.longValue());
+        }
+        else if ((type == Short.TYPE) || (type == Short.class))
+        {
+            return new Short(value.shortValue());
+        }
+        else if (type == BigDecimal.class)
+        {
+            if (value instanceof BigDecimal)
+            {
+                return (BigDecimal) value;
+            }
+            else if (value instanceof BigInteger)
+            {
+                return new BigDecimal((BigInteger) value);
+            }
+            else
+            {
+                return new BigDecimal(((Number) value).doubleValue());
+            }
+        }
+        else if (type == BigInteger.class)
+        {
+            if (value instanceof BigInteger)
+            {
+                return (BigInteger) value;
+            }
+            else if (value instanceof BigDecimal)
+            {
+                return ((BigDecimal) value).toBigInteger();
+            }
+            else
+            {
+                return BigInteger.valueOf(((Number) value).longValue());
+            }
+        }
+        throw new IllegalArgumentException("Cannot convert " + value + " to "
+                + type.getName());
+
+    }
+
+    /**
+     * <p>Coerce the specified value to the specified Number subclass.</p>
+     *
+     * @param value Value to be coerced
+     * @param type Destination type
+     */
+    private Number coerce(String value, Class type)
+    {
+
+        if ((type == Byte.TYPE) || (type == Byte.class))
+        {
+            return Byte.valueOf(value);
+        }
+        else if ((type == Double.TYPE) || (type == Double.class))
+        {
+            return Double.valueOf(value);
+        }
+        else if ((type == Float.TYPE) || (type == Float.class))
+        {
+            return Float.valueOf(value);
+        }
+        else if ((type == Integer.TYPE) || (type == Integer.class))
+        {
+            return Integer.valueOf(value);
+        }
+        else if ((type == Long.TYPE) || (type == Long.class))
+        {
+            return Long.valueOf(value);
+        }
+        else if ((type == Short.TYPE) || (type == Short.class))
+        {
+            return Short.valueOf(value);
+        }
+        else if (type == BigDecimal.class)
+        {
+            return new BigDecimal(value);
+        }
+        else if (type == BigInteger.class)
+        {
+            return new BigInteger(value);
+        }
+        throw new IllegalArgumentException("Cannot convert " + value + " to "
+                + type.getName());
+
+    }
+
+    /**
+     * <p>Return <code>true</code> if the specified type is numeric.</p>
+     *
+     * @param type Type to check
+     */
+    private boolean isNumeric(Class type)
+    {
+
+        return (type == Byte.TYPE) || (type == Byte.class)
+                || (type == Double.TYPE) || (type == Double.class)
+                || (type == Float.TYPE) || (type == Float.class)
+                || (type == Integer.TYPE) || (type == Integer.class)
+                || (type == Long.TYPE) || (type == Long.class)
+                || (type == Short.TYPE) || (type == Short.class)
+                || (type == BigDecimal.class) || (type == BigInteger.class);
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/el/MockFunctionMapper.java b/test/src/main/java/org/apache/myfaces/test/el/MockFunctionMapper.java
new file mode 100644
index 0000000..4d7d15d
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/el/MockFunctionMapper.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.el;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import javax.el.FunctionMapper;
+
+/**
+ * <p>Mock implementation of <code>FunctionMapper</code>.</p>
+ *
+ * @since 1.0.0
+ */
+
+public class MockFunctionMapper extends FunctionMapper
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /** Creates a new instance of MockFunctionMapper */
+    public MockFunctionMapper()
+    {
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>Map of <code>Method</code> descriptors for static methods, keyed by
+     * a string composed of the prefix (or "" if none), a ":", and the local name.</p>
+     */
+    private Map functions = new HashMap();
+
+    // ----------------------------------------------------- Mock Object Methods
+
+    /**
+     * <p>Store a mapping of the specified prefix and localName to the
+     * specified method, which must be static.</p>
+     */
+    public void mapFunction(String prefix, String localName, Method method)
+    {
+
+        functions.put(prefix + ":" + localName, method);
+
+    }
+
+    // -------------------------------------------------- FunctionMapper Methods
+
+    /** {@inheritDoc} */
+    public Method resolveFunction(String prefix, String localName)
+    {
+
+        return (Method) functions.get(prefix + ":" + localName);
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/el/MockMethodExpression.java b/test/src/main/java/org/apache/myfaces/test/el/MockMethodExpression.java
new file mode 100644
index 0000000..04b065a
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/el/MockMethodExpression.java
@@ -0,0 +1,267 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.el;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import javax.el.ELContext;
+import javax.el.ELException;
+import javax.el.ELResolver;
+import javax.el.MethodExpression;
+import javax.el.MethodInfo;
+import javax.el.MethodNotFoundException;
+import javax.faces.context.FacesContext;
+
+/**
+ * <p>Mock implementation of <code>MethodExpression</code>.</p>
+ * 
+ * @since 1.0.0
+ */
+public class MockMethodExpression extends MethodExpression
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * Serial version UID.
+     */
+    private static final long serialVersionUID = 5694105394290316715L;
+
+    /**
+     * <p>Construct a new expression for the specified expression string.</p>
+     *
+     * @param expression Expression string to be evaluated
+     * @param signature Parameter signature of the method to be called
+     * @param expectedType Expected type of the result
+     */
+    public MockMethodExpression(String expression, Class[] signature,
+            Class expectedType)
+    {
+
+        if (expression == null)
+        {
+            throw new NullPointerException("Expression string cannot be null");
+        }
+        this.expression = expression;
+        this.signature = signature;
+        this.expectedType = expectedType;
+        parse();
+
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>The parsed elements of this expression.</p>
+     */
+    private String[] elements = null;
+
+    /**
+     * <p>The expected result type for <code>getValue()</code> calls.</p>
+     */
+    private Class expectedType = null;
+
+    /**
+     * <p>The original expression string used to create this expression.</p>
+     */
+    private String expression = null;
+
+    /**
+     * <p>The method signature of the method to be called.</p>
+     */
+    private Class[] signature = null;
+
+    // ------------------------------------------------------ Expression Methods
+
+    /**
+     * <p>Return <code>true</code> if this expression is equal to the
+     * specified expression.</p>
+     *
+     * @param obj Object to be compared
+     */
+    public boolean equals(Object obj)
+    {
+
+        if ((obj != null) & (obj instanceof MethodExpression))
+        {
+            return expression.equals(((MethodExpression) obj)
+                    .getExpressionString());
+        }
+        else
+        {
+            return false;
+        }
+
+    }
+
+    /**
+     * <p>Return the original String used to create this expression,
+     * unmodified.</p>
+     */
+    public String getExpressionString()
+    {
+
+        return this.expression;
+
+    }
+
+    /**
+     * <p>Return the hash code for this expression.</p>
+     */
+    public int hashCode()
+    {
+
+        return this.expression.hashCode();
+
+    }
+
+    /**
+     * <p>Return <code>true</code> if the expression string for this expression
+     * contains only literal text.</p>
+     */
+    public boolean isLiteralText()
+    {
+
+        return (expression.indexOf("${") < 0) && (expression.indexOf("#{") < 0);
+
+    }
+
+    // ------------------------------------------------ MethodExpression Methods
+
+    /**
+     * <p>Evaluate the expression relative to the specified context,
+     * and return information about the actual implementation method.</p>
+     *
+     * @param context ELContext for this evaluation
+     */
+    public MethodInfo getMethodInfo(ELContext context)
+    {
+
+        if (context == null)
+        {
+            throw new NullPointerException();
+        }
+        return new MethodInfo(elements[elements.length - 1], expectedType,
+                signature);
+
+    }
+
+    /**
+     * <p>Evaluate the expression relative to the specified ocntext,
+     * and return the result after coercion to the expected result type.</p>
+     *
+     * @param context ELContext for this evaluation
+     * @param params Parameters for this method call
+     */
+    public Object invoke(ELContext context, Object[] params)
+    {
+
+        if (context == null)
+        {
+            throw new NullPointerException();
+        }
+        if (isLiteralText())
+        {
+            return expression;
+        }
+
+        FacesContext fcontext = (FacesContext) context
+                .getContext(FacesContext.class);
+        ELResolver resolver = fcontext.getApplication().getELResolver();
+        Object base = null;
+        for (int i = 0; i < elements.length - 1; i++)
+        {
+            base = resolver.getValue(context, base, elements[i]);
+        }
+
+        try
+        {
+            Method method = base.getClass().getMethod(
+                    elements[elements.length - 1], signature);
+            Object result = method.invoke(base, params);
+            return fcontext.getApplication().getExpressionFactory()
+                    .coerceToType(result, expectedType);
+        }
+        catch (RuntimeException e)
+        {
+            throw e;
+        }
+        catch (NoSuchMethodException e)
+        {
+            throw new MethodNotFoundException(e);
+        }
+        catch (Exception e)
+        {
+            throw new ELException(e);
+        }
+
+    }
+
+    // --------------------------------------------------------- Private Methods
+
+    /**
+     * <p>Parse the expression string into its constituent elemetns.</p>
+     */
+    private void parse()
+    {
+
+        if (isLiteralText())
+        {
+            elements = new String[0];
+            return;
+        }
+
+        if (expression.startsWith("${") || expression.startsWith("#{"))
+        {
+            if (expression.endsWith("}"))
+            {
+                String temp = expression.substring(2, expression.length() - 1)
+                        .replaceAll(" ", "");
+                List names = new ArrayList();
+                while (temp.length() > 0)
+                {
+                    int period = temp.indexOf(".");
+                    if (period >= 0)
+                    {
+                        names.add(temp.substring(0, period));
+                        temp = temp.substring(period + 1);
+                    }
+                    else
+                    {
+                        names.add(temp);
+                        temp = "";
+                    }
+                }
+                elements = (String[]) names.toArray(new String[names.size()]);
+            }
+            else
+            {
+                throw new IllegalArgumentException(expression);
+            }
+        }
+        else
+        {
+            throw new IllegalArgumentException(expression);
+        }
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/el/MockValueExpression.java b/test/src/main/java/org/apache/myfaces/test/el/MockValueExpression.java
new file mode 100644
index 0000000..8489ea7
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/el/MockValueExpression.java
@@ -0,0 +1,307 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.el;
+
+import javax.el.ELContext;
+import javax.el.ELResolver;
+import javax.el.ValueExpression;
+import javax.faces.context.FacesContext;
+
+/**
+ * <p>Mock implementation of <code>ValueExpression</code>.</p>
+ *
+ * <p>This implementation supports a limited subset of overall expression functionality:</p>
+ * <ul>
+ * <li>A literal string that contains no expression delimiters.</li>
+ * <li>An expression that starts with "#{" or "${", and ends with "}".</li>
+ * </ul>
+ * 
+ * @since 1.0.0
+ */
+public class MockValueExpression extends ValueExpression
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * Serial version UID.
+     */
+    private static final long serialVersionUID = -8649071428507512623L;
+
+    /**
+     * <p>Construct a new expression for the specified expression string.</p>
+     *
+     * @param expression Expression string to be evaluated
+     * @param expectedType Expected type of the result
+     */
+    public MockValueExpression(String expression, Class expectedType)
+    {
+
+        if (expression == null)
+        {
+            throw new NullPointerException("Expression string cannot be null");
+        }
+        this.expression = expression;
+        this.expectedType = expectedType;
+        parse();
+
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>The parsed elements of this expression.</p>
+     */
+    private String[] elements = null;
+
+    /**
+     * <p>The expected result type for <code>getValue()</code> calls.</p>
+     */
+    private Class expectedType = null;
+
+    /**
+     * <p>The original expression string used to create this expression.</p>
+     */
+    private String expression = null;
+
+    // ------------------------------------------------------ Expression Methods
+
+    /**
+     * <p>Return <code>true</code> if this expression is equal to the
+     * specified expression.</p>
+     *
+     * @param obj Object to be compared
+     */
+    public boolean equals(Object obj)
+    {
+
+        if ((obj != null) & (obj instanceof ValueExpression))
+        {
+            return expression.equals(((ValueExpression) obj)
+                    .getExpressionString());
+        }
+        else
+        {
+            return false;
+        }
+
+    }
+
+    /**
+     * <p>Return the original String used to create this expression,
+     * unmodified.</p>
+     */
+    public String getExpressionString()
+    {
+
+        return this.expression;
+
+    }
+
+    /**
+     * <p>Return the hash code for this expression.</p>
+     */
+    public int hashCode()
+    {
+
+        return this.expression.hashCode();
+
+    }
+
+    /**
+     * <p>Return <code>true</code> if the expression string for this expression
+     * contains only literal text.</p>
+     */
+    public boolean isLiteralText()
+    {
+
+        return (expression.indexOf("${") < 0) && (expression.indexOf("#{") < 0);
+
+    }
+
+    // ------------------------------------------------- ValueExpression Methods
+
+    /**
+     * <p>Return the type that the result of this expression will
+     * be coerced to.</p>
+     */
+    public Class getExpectedType()
+    {
+
+        return this.expectedType;
+
+    }
+
+    /**
+     * <p>Evaluate this expression relative to the specified context,
+     * and return the most general type that is acceptable for the
+     * value passed in a <code>setValue()</code> call.</p>
+     *
+     * @param context ELContext for this evaluation
+     */
+    public Class getType(ELContext context)
+    {
+
+        if (context == null)
+        {
+            throw new NullPointerException();
+        }
+        Object value = getValue(context);
+        if (value == null)
+        {
+            if (isLiteralText())
+            {
+                return String.class;
+            }
+
+            ELResolver resolver = context.getELResolver();
+            Object base = null;
+            for (int i = 0; i < elements.length - 1; i++)
+            {
+                base = resolver.getValue(context, base, elements[i]);
+            }
+            return resolver.getType(context, base, elements[elements.length - 1]);
+        }
+        else
+        {
+            return value.getClass();
+        }
+    }
+
+    /**
+     * <p>Evaluate this expression relative to the specified context,
+     * and return the result.</p>
+     *
+     * @param context ELContext for this evaluation
+     */
+    public Object getValue(ELContext context)
+    {
+
+        if (context == null)
+        {
+            throw new NullPointerException();
+        }
+        if (isLiteralText())
+        {
+            return expression;
+        }
+
+        FacesContext fcontext = (FacesContext) context
+                .getContext(FacesContext.class);
+
+        ELResolver resolver = context.getELResolver();
+        Object base = null;
+        for (int i = 0; i < elements.length; i++)
+        {
+            base = resolver.getValue(context, base, elements[i]);
+        }
+        return fcontext.getApplication().getExpressionFactory().coerceToType(
+                base, getExpectedType());
+
+    }
+
+    /**
+     * <p>Evaluate this expression relative to the specified context,
+     * and return <code>true</code> if a call to <code>setValue()</code>
+     * will always fail.</p>
+     *
+     * @param context ELContext for this evaluation
+     */
+    public boolean isReadOnly(ELContext context)
+    {
+
+        if (context == null)
+        {
+            throw new NullPointerException();
+        }
+        if (isLiteralText())
+        {
+            return true;
+        }
+
+        ELResolver resolver = context.getELResolver();
+        Object base = null;
+        for (int i = 0; i < elements.length - 1; i++)
+        {
+            base = resolver.getValue(context, base, elements[i]);
+        }
+        return resolver
+                .isReadOnly(context, base, elements[elements.length - 1]);
+
+    }
+
+    /**
+     * <p>Evaluate this expression relative to the specified context,
+     * and set the result to the specified value.</p>
+     *
+     * @param context ELContext for this evaluation
+     * @param value Value to which the result should be set
+     */
+    public void setValue(ELContext context, Object value)
+    {
+
+        if (context == null)
+        {
+            throw new NullPointerException();
+        }
+
+        ELResolver resolver = context.getELResolver();
+        Object base = null;
+        for (int i = 0; i < elements.length - 1; i++)
+        {
+            base = resolver.getValue(context, base, elements[i]);
+        }
+        resolver.setValue(context, base, elements[elements.length - 1], value);
+
+    }
+
+    // --------------------------------------------------------- Private Methods
+
+    /**
+     * <p>Parse the expression string into its constituent elemetns.</p>
+     */
+    private void parse()
+    {
+
+        if (isLiteralText())
+        {
+            elements = new String[0];
+            return;
+        }
+
+        if (expression.startsWith("${") || expression.startsWith("#{"))
+        {
+            if (expression.endsWith("}"))
+            {
+                elements = ExpressionTokenizer.tokenize(expression.substring(2, expression.length() - 1));
+            }
+            else
+            {
+                throw new IllegalArgumentException(expression);
+            }
+        }
+        else
+        {
+            throw new IllegalArgumentException(expression);
+        }
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/el/MockVariableMapper.java b/test/src/main/java/org/apache/myfaces/test/el/MockVariableMapper.java
new file mode 100644
index 0000000..b19e7bd
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/el/MockVariableMapper.java
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.el;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.el.ValueExpression;
+import javax.el.VariableMapper;
+
+/**
+ * <p>Mock implementation of <code>VariableMapper</code>.</p>
+ *
+ * @since 1.0.0
+ */
+
+public class MockVariableMapper extends VariableMapper
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /** Creates a new instance of MockVariableMapper */
+    public MockVariableMapper()
+    {
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>Map of <code>ValueExpression</code>s, keyed by variable name.</p>
+     */
+    private Map expressions = new HashMap();
+
+    // ----------------------------------------------------- Mock Object Methods
+
+    // -------------------------------------------------- FunctionMapper Methods
+
+    /** {@inheritDoc} */
+    public ValueExpression resolveVariable(String variable)
+    {
+
+        return (ValueExpression) expressions.get(variable);
+
+    }
+
+    /** {@inheritDoc} */
+    public ValueExpression setVariable(String variable,
+            ValueExpression expression)
+    {
+
+        ValueExpression original = (ValueExpression) expressions.get(variable);
+        if (expression == null)
+        {
+            expressions.remove(variable);
+        }
+        else
+        {
+            expressions.put(variable, expression);
+        }
+        return original;
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/el/MockVariableValueExpression.java b/test/src/main/java/org/apache/myfaces/test/el/MockVariableValueExpression.java
new file mode 100644
index 0000000..734d911
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/el/MockVariableValueExpression.java
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.el;
+
+import javax.el.ELContext;
+import javax.el.PropertyNotWritableException;
+import javax.el.ValueExpression;
+import javax.faces.context.FacesContext;
+
+/**
+ * <p>Mock implementation of <code>ValueExpression</code> that wraps a variable.</p>
+ * 
+ * @since 1.0.0
+ */
+public class MockVariableValueExpression extends ValueExpression
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * Serial version UID.
+     */
+    private static final long serialVersionUID = 4475919948345298291L;
+
+    /**
+     * <p>Construct a new expression for the specified instance.</p>
+     *
+     * @param instance Variable instance to be wrapped
+     * @param expectedType Expected type of the result
+     */
+    public MockVariableValueExpression(Object instance, Class expectedType)
+    {
+
+        if (instance == null)
+        {
+            throw new NullPointerException("Instance cannot be null");
+        }
+        this.instance = instance;
+        this.expectedType = expectedType;
+
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>The expected result type for <code>getValue()</code> calls.</p>
+     */
+    private Class expectedType = null;
+
+    /**
+     * <p>The variable instance being wrapped by this expression.</p>
+     */
+    private Object instance = null;
+
+    // ------------------------------------------------------ Expression Methods
+
+    /**
+     * <p>Return <code>true</code> if this expression is equal to the
+     * specified expression.</p>
+     *
+     * @param obj Object to be compared
+     */
+    public boolean equals(Object obj)
+    {
+
+        if ((obj != null) & (obj instanceof ValueExpression))
+        {
+            return instance.toString().equals(
+                    ((ValueExpression) obj).getExpressionString());
+        }
+        else
+        {
+            return false;
+        }
+
+    }
+
+    /**
+     * <p>Return the original String used to create this expression,
+     * unmodified.</p>
+     */
+    public String getExpressionString()
+    {
+
+        return this.instance.toString();
+
+    }
+
+    /**
+     * <p>Return the hash code for this expression.</p>
+     */
+    public int hashCode()
+    {
+
+        return this.instance.toString().hashCode();
+
+    }
+
+    /**
+     * <p>Return <code>true</code> if the expression string for this expression
+     * contains only literal text.</p>
+     */
+    public boolean isLiteralText()
+    {
+
+        return true;
+
+    }
+
+    // ------------------------------------------------- ValueExpression Methods
+
+    /**
+     * <p>Return the type that the result of this expression will
+     * be coerced to.</p>
+     */
+    public Class getExpectedType()
+    {
+
+        return this.expectedType;
+
+    }
+
+    /**
+     * <p>Evaluate this expression relative to the specified context,
+     * and return the most general type that is acceptable for the
+     * value passed in a <code>setValue()</code> call.</p>
+     *
+     * @param context ELContext for this evaluation
+     */
+    public Class getType(ELContext context)
+    {
+
+        if (context == null)
+        {
+            throw new NullPointerException();
+        }
+        return this.instance.getClass();
+
+    }
+
+    /**
+     * <p>Evaluate this expression relative to the specified context,
+     * and return the result.</p>
+     *
+     * @param context ELContext for this evaluation
+     */
+    public Object getValue(ELContext context)
+    {
+
+        if (context == null)
+        {
+            throw new NullPointerException();
+        }
+        FacesContext fcontext = (FacesContext) context
+                .getContext(FacesContext.class);
+        return fcontext.getApplication().getExpressionFactory().coerceToType(
+                instance, expectedType);
+
+    }
+
+    /**
+     * <p>Evaluate this expression relative to the specified context,
+     * and return <code>true</code> if a call to <code>setValue()</code>
+     * will always fail.</p>
+     *
+     * @param context ELContext for this evaluation
+     */
+    public boolean isReadOnly(ELContext context)
+    {
+
+        if (context == null)
+        {
+            throw new NullPointerException();
+        }
+        return true;
+
+    }
+
+    /**
+     * <p>Evaluate this expression relative to the specified context,
+     * and set the result to the specified value.</p>
+     *
+     * @param context ELContext for this evaluation
+     * @param value Value to which the result should be set
+     */
+    public void setValue(ELContext context, Object value)
+    {
+
+        if (context == null)
+        {
+            throw new NullPointerException();
+        }
+
+        throw new PropertyNotWritableException();
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/el/ReservedWordsELResolver.java b/test/src/main/java/org/apache/myfaces/test/el/ReservedWordsELResolver.java
new file mode 100644
index 0000000..2c048b5
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/el/ReservedWordsELResolver.java
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+package org.apache.myfaces.test.el;
+
+import java.beans.FeatureDescriptor;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.el.ELContext;
+import javax.el.PropertyNotWritableException;
+
+/**
+ * {@code ELResolver} for reserved words.
+ */
+public class ReservedWordsELResolver extends AbstractELResolver
+{
+
+    private static final Map<String, Object> VALUES;
+
+    static
+    {
+        HashMap<String, Object> values = new HashMap<String, Object>();
+        values.put("true", Boolean.TRUE);
+        values.put("false", Boolean.FALSE);
+        values.put("null", null);
+        VALUES = Collections.unmodifiableMap(values);
+    }
+
+    private List<FeatureDescriptor> featureDescriptors;
+
+    @Override
+    public Object getValue(ELContext context, Object base, Object property)
+    {
+        if (base == null && VALUES.containsKey(property))
+        {
+            context.setPropertyResolved(true);
+            return VALUES.get(property);
+        }
+        return null;
+    }
+
+    @Override
+    public Class<?> getType(ELContext context, Object base, Object property)
+    {
+        if (base == null && VALUES.containsKey(property))
+        {
+            context.setPropertyResolved(true);
+            Object value = VALUES.get(property);
+            return value == null ? null : value.getClass();
+        }
+        return null;
+    }
+
+    @Override
+    public void setValue(ELContext context, Object base, Object property,
+        Object value)
+    {
+        if (base == null && VALUES.containsKey(property))
+        {
+            context.setPropertyResolved(true);
+            throw new PropertyNotWritableException(property.toString());
+        }
+    }
+
+    @Override
+    public boolean isReadOnly(ELContext context, Object base, Object property)
+    {
+        if (base == null && VALUES.containsKey(property))
+        {
+            context.setPropertyResolved(true);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public synchronized Iterator<FeatureDescriptor> getFeatureDescriptors(
+        ELContext context, Object base)
+    {
+        if (featureDescriptors == null)
+        {
+            featureDescriptors = new ArrayList<FeatureDescriptor>();
+            for (Map.Entry<String, Object> e : VALUES.entrySet())
+            {
+                final Class<?> type
+                    = e.getValue() == null ? null : e.getValue().getClass();
+                featureDescriptors.add(descriptor(e.getKey(), e.getKey(),
+                    e.getKey(), false, false, true, type, true));
+            }
+            featureDescriptors
+                = Collections.unmodifiableList(featureDescriptors);
+        }
+        return featureDescriptors.iterator();
+    }
+
+    @Override
+    public Class<?> getCommonPropertyType(ELContext context, Object base)
+    {
+        return base == null ? String.class : null;
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/htmlunit/AbstractHtmlUnitTestCase.java b/test/src/main/java/org/apache/myfaces/test/htmlunit/AbstractHtmlUnitTestCase.java
new file mode 100644
index 0000000..b1e62b0
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/htmlunit/AbstractHtmlUnitTestCase.java
@@ -0,0 +1,333 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.htmlunit;
+
+import com.gargoylesoftware.htmlunit.ElementNotFoundException;
+import com.gargoylesoftware.htmlunit.WebClient;
+import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
+import com.gargoylesoftware.htmlunit.html.HtmlBody;
+import com.gargoylesoftware.htmlunit.html.HtmlElement;
+import com.gargoylesoftware.htmlunit.html.HtmlForm;
+import com.gargoylesoftware.htmlunit.html.HtmlHead;
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Iterator;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * <p>Abstract base class for system integration tests based on HtmlUnit.
+ * These tests will expect a system property named <code>url</code> to be
+ * present, which will define the URL (including the context path, but
+ * without a trailing slash) of the application to be tested.</p>
+ * 
+ * @since 1.0.0
+ */
+public abstract class AbstractHtmlUnitTestCase extends TestCase
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct a new instance of this test case.</p>
+     *
+     * @param name Name of the new test case
+     */
+    public AbstractHtmlUnitTestCase(String name)
+    {
+
+        super(name);
+
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>The most recently retrieved page from the server.</p>
+     */
+    protected HtmlPage page = null;
+
+    /**
+     * <p>The calculated URL for the installed "systest" web application.
+     * This value is based on a system property named <code>url</code>,
+     * which must be defined as part of the command line that executes
+     * each test case.</p>
+     */
+    protected URL url = null;
+
+    /**
+     * <p>The web client for this test case.</p>
+     */
+    protected WebClient webClient = null;
+
+    // ------------------------------------------------------ Test Setup Methods
+
+    /**
+     * <p>Set up the instance variables required for this test case.</p>
+     *
+     * @exception Exception if an error occurs
+     */
+    protected void setUp() throws Exception
+    {
+
+        // Calculate the URL for the installed "systest" web application
+        String url = System.getProperty("url");
+        this.url = new URL(url + "/");
+
+        // Initialize HtmlUnit constructs for this test case
+        webClient = new WebClient();
+
+    }
+
+    /**
+     * <p>Return the set of tests included in this test suite.</p>
+     */
+    public static Test suite()
+    {
+
+        return (new TestSuite(AbstractHtmlUnitTestCase.class));
+
+    }
+
+    /**
+     * <p>Tear down instance variables required by this test case.</p>
+     */
+    protected void tearDown() throws Exception
+    {
+
+        page = null;
+        url = null;
+        webClient = null;
+
+    }
+
+    // ------------------------------------------------------- Protected Methods
+
+    /**
+     * <p>Return the body element for the most recently retrieved page.
+     * If there is no such element, return <code>null</code>.</p>
+     *
+     * @exception Exception if an error occurs
+     */
+    protected HtmlBody body() throws Exception
+    {
+
+        Iterator elements = page.getAllHtmlChildElements();
+        while (elements.hasNext())
+        {
+            HtmlElement element = (HtmlElement) elements.next();
+            if (element instanceof HtmlBody)
+            {
+                return ((HtmlBody) element);
+            }
+        }
+        return (null);
+
+    }
+
+    /**
+     * <p>Return the HTML element with the specified <code>id</code> from the
+     * most recently retrieved page.  If there is no such element, return
+     * <code>null</code>.</p>
+     *
+     * @param id Identifier of the requested element.
+     *
+     * @exception Exception if an error occurs
+     */
+    protected HtmlElement element(String id) throws Exception
+    {
+
+        try
+        {
+            return (page.getHtmlElementById(id));
+        }
+        catch (ElementNotFoundException e)
+        {
+            return (null);
+        }
+
+    }
+
+    /**
+     * <p>Return the form with the specified <code>id</code> from the most
+     * recently retrieved page.  If there is no such form, return
+     * <code>null</code>.<p>
+     *
+     * @param id Identifier of the requested form.
+     *
+     * @exception Exception if an error occurs
+     */
+    protected HtmlForm form(String id) throws Exception
+    {
+
+        Iterator forms = page.getForms().iterator();
+        while (forms.hasNext())
+        {
+            HtmlForm form = (HtmlForm) forms.next();
+            if (id.equals(form.getAttributeValue("id")))
+            {
+                return (form);
+            }
+        }
+        return (null);
+
+    }
+
+    /**
+     * <p>Return the head element for the most recently retrieved page.
+     * If there is no such element, return <code>null</code>.</p>
+     *
+     * @exception Exception if an error occurs
+     */
+    protected HtmlHead head() throws Exception
+    {
+
+        Iterator elements = page.getAllHtmlChildElements();
+        while (elements.hasNext())
+        {
+            HtmlElement element = (HtmlElement) elements.next();
+            if (element instanceof HtmlHead)
+            {
+                return ((HtmlHead) element);
+            }
+        }
+        return (null);
+
+    }
+
+    /**
+     * <p>Click the specified hyperlink, and retrieve the subsequent page,
+     * saving a reference so that other utility methods may be used to
+     * retrieve information from it.</p>
+     *
+     * @param anchor Anchor component to click
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    protected HtmlPage link(HtmlAnchor anchor) throws IOException
+    {
+
+        HtmlPage page = (HtmlPage) anchor.click();
+        this.page = page;
+        return page;
+
+    }
+
+    /**
+     * <p>Return the currently stored page reference.</p>
+     */
+    protected HtmlPage page()
+    {
+
+        return this.page;
+
+    }
+
+    /**
+     * <p>Retrieve and return the page at the specified context relative path.
+     * Save a reference to this page so that other utility methods may be used
+     * to retrieve information from it.</p>
+     *
+     * @param path Context relative path
+     *
+     * @exception IllegalArgumentException if the context relative path
+     *  does not begin with a '/' character
+     * @exception Exception if a different error occurs
+     */
+    protected HtmlPage page(String path) throws Exception
+    {
+
+        HtmlPage page = (HtmlPage) webClient.getPage(url(path));
+        this.page = page;
+        return (page);
+
+    }
+
+    /**
+     * <p>Reset the stored page reference to the specified value.  This is
+     * useful for scenarios testing resubmit of the same page (simulating the
+     * user pressing the back button and then submitting again).</p>
+     *
+     * @param page Previously saved page to which to reset
+     */
+    protected void reset(HtmlPage page)
+    {
+
+        this.page = page;
+
+    }
+
+    /**
+     * <p>Submit the current page, using the specified component, and retrieve
+     * the subsequent page, saving a reference so that other utility methods
+     * may be used to retrieve information from it.</p>
+     *
+     * @param submit Submit button component to click
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    protected HtmlPage submit(HtmlSubmitInput submit) throws IOException
+    {
+
+        HtmlPage page = (HtmlPage) submit.click();
+        this.page = page;
+        return page;
+
+    }
+
+    /**
+     * <p>Return the page title from the most recently retrieved page.
+     * Any leading and trailing whitespace will be trimmed.</p>
+     *
+     * @exception Exception if an error occurs
+     */
+    protected String title() throws Exception
+    {
+
+        return (page.getTitleText().trim());
+
+    }
+
+    /**
+     * <p>Calculate and return an absolute URL for the specified context
+     * relative path, which must begin with a '/' character.</p>
+     *
+     * @param path Context relative path
+     *
+     * @exception IllegalArgumentException if the context relative path
+     *  does not begin with a '/' character
+     * @exception Exception if a different error ocurs
+     */
+    protected URL url(String path) throws Exception
+    {
+
+        if (path.charAt(0) != '/')
+        {
+            throw new IllegalArgumentException("Context path '" + path
+                    + "' does not start with '/'");
+        }
+        return new URL(url, path.substring(1));
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/htmlunit/junit4/AbstractHtmlUnitTestCase.java b/test/src/main/java/org/apache/myfaces/test/htmlunit/junit4/AbstractHtmlUnitTestCase.java
new file mode 100644
index 0000000..648b1de
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/htmlunit/junit4/AbstractHtmlUnitTestCase.java
@@ -0,0 +1,322 @@
+/*
+ * 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.
+ */
+package org.apache.myfaces.test.htmlunit.junit4;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Iterator;
+
+import org.junit.After;
+import org.junit.Before;
+
+import com.gargoylesoftware.htmlunit.ElementNotFoundException;
+import com.gargoylesoftware.htmlunit.WebClient;
+import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
+import com.gargoylesoftware.htmlunit.html.HtmlBody;
+import com.gargoylesoftware.htmlunit.html.HtmlElement;
+import com.gargoylesoftware.htmlunit.html.HtmlForm;
+import com.gargoylesoftware.htmlunit.html.HtmlHead;
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
+
+/**
+ * <p>Abstract base class for system integration tests based on HtmlUnit.
+ * These tests will expect a system property named <code>url</code> to be
+ * present, which will define the URL (including the context path, but
+ * without a trailing slash) of the application to be tested.</p>
+ * 
+ * @since 1.0.0
+ */
+public abstract class AbstractHtmlUnitTestCase
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct a new instance of this test case.</p>
+     *
+     * @param name Name of the new test case
+     */
+    public AbstractHtmlUnitTestCase()
+    {
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>The most recently retrieved page from the server.</p>
+     */
+    protected HtmlPage page = null;
+
+    /**
+     * <p>The calculated URL for the installed "systest" web application.
+     * This value is based on a system property named <code>url</code>,
+     * which must be defined as part of the command line that executes
+     * each test case.</p>
+     */
+    protected URL url = null;
+
+    /**
+     * <p>The web client for this test case.</p>
+     */
+    protected WebClient webClient = null;
+
+    // ------------------------------------------------------ Test Setup Methods
+
+    /**
+     * <p>Set up the instance variables required for this test case.</p>
+     *
+     * @exception Exception if an error occurs
+     */
+    @Before
+    protected void setUp() throws Exception
+    {
+
+        // Calculate the URL for the installed "systest" web application
+        String url = System.getProperty("url");
+        this.url = new URL(url + "/");
+
+        // Initialize HtmlUnit constructs for this test case
+        webClient = new WebClient();
+
+    }
+
+    /**
+     * <p>Tear down instance variables required by this test case.</p>
+     */
+    @After
+    protected void tearDown() throws Exception
+    {
+
+        page = null;
+        url = null;
+        webClient = null;
+
+    }
+
+    // ------------------------------------------------------- Protected Methods
+
+    /**
+     * <p>Return the body element for the most recently retrieved page.
+     * If there is no such element, return <code>null</code>.</p>
+     *
+     * @exception Exception if an error occurs
+     */
+    protected HtmlBody body() throws Exception
+    {
+
+        Iterator elements = page.getAllHtmlChildElements();
+        while (elements.hasNext())
+        {
+            HtmlElement element = (HtmlElement) elements.next();
+            if (element instanceof HtmlBody)
+            {
+                return ((HtmlBody) element);
+            }
+        }
+        return (null);
+
+    }
+
+    /**
+     * <p>Return the HTML element with the specified <code>id</code> from the
+     * most recently retrieved page.  If there is no such element, return
+     * <code>null</code>.</p>
+     *
+     * @param id Identifier of the requested element.
+     *
+     * @exception Exception if an error occurs
+     */
+    protected HtmlElement element(String id) throws Exception
+    {
+
+        try
+        {
+            return (page.getHtmlElementById(id));
+        }
+        catch (ElementNotFoundException e)
+        {
+            return (null);
+        }
+
+    }
+
+    /**
+     * <p>Return the form with the specified <code>id</code> from the most
+     * recently retrieved page.  If there is no such form, return
+     * <code>null</code>.<p>
+     *
+     * @param id Identifier of the requested form.
+     *
+     * @exception Exception if an error occurs
+     */
+    protected HtmlForm form(String id) throws Exception
+    {
+
+        Iterator forms = page.getForms().iterator();
+        while (forms.hasNext())
+        {
+            HtmlForm form = (HtmlForm) forms.next();
+            if (id.equals(form.getAttributeValue("id")))
+            {
+                return (form);
+            }
+        }
+        return (null);
+
+    }
+
+    /**
+     * <p>Return the head element for the most recently retrieved page.
+     * If there is no such element, return <code>null</code>.</p>
+     *
+     * @exception Exception if an error occurs
+     */
+    protected HtmlHead head() throws Exception
+    {
+
+        Iterator elements = page.getAllHtmlChildElements();
+        while (elements.hasNext())
+        {
+            HtmlElement element = (HtmlElement) elements.next();
+            if (element instanceof HtmlHead)
+            {
+                return ((HtmlHead) element);
+            }
+        }
+        return (null);
+
+    }
+
+    /**
+     * <p>Click the specified hyperlink, and retrieve the subsequent page,
+     * saving a reference so that other utility methods may be used to
+     * retrieve information from it.</p>
+     *
+     * @param anchor Anchor component to click
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    protected HtmlPage link(HtmlAnchor anchor) throws IOException
+    {
+
+        HtmlPage page = (HtmlPage) anchor.click();
+        this.page = page;
+        return page;
+
+    }
+
+    /**
+     * <p>Return the currently stored page reference.</p>
+     */
+    protected HtmlPage page()
+    {
+
+        return this.page;
+
+    }
+
+    /**
+     * <p>Retrieve and return the page at the specified context relative path.
+     * Save a reference to this page so that other utility methods may be used
+     * to retrieve information from it.</p>
+     *
+     * @param path Context relative path
+     *
+     * @exception IllegalArgumentException if the context relative path
+     *  does not begin with a '/' character
+     * @exception Exception if a different error occurs
+     */
+    protected HtmlPage page(String path) throws Exception
+    {
+
+        HtmlPage page = (HtmlPage) webClient.getPage(url(path));
+        this.page = page;
+        return (page);
+
+    }
+
+    /**
+     * <p>Reset the stored page reference to the specified value.  This is
+     * useful for scenarios testing resubmit of the same page (simulating the
+     * user pressing the back button and then submitting again).</p>
+     *
+     * @param page Previously saved page to which to reset
+     */
+    protected void reset(HtmlPage page)
+    {
+
+        this.page = page;
+
+    }
+
+    /**
+     * <p>Submit the current page, using the specified component, and retrieve
+     * the subsequent page, saving a reference so that other utility methods
+     * may be used to retrieve information from it.</p>
+     *
+     * @param submit Submit button component to click
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    protected HtmlPage submit(HtmlSubmitInput submit) throws IOException
+    {
+
+        HtmlPage page = (HtmlPage) submit.click();
+        this.page = page;
+        return page;
+
+    }
+
+    /**
+     * <p>Return the page title from the most recently retrieved page.
+     * Any leading and trailing whitespace will be trimmed.</p>
+     *
+     * @exception Exception if an error occurs
+     */
+    protected String title() throws Exception
+    {
+
+        return (page.getTitleText().trim());
+
+    }
+
+    /**
+     * <p>Calculate and return an absolute URL for the specified context
+     * relative path, which must begin with a '/' character.</p>
+     *
+     * @param path Context relative path
+     *
+     * @exception IllegalArgumentException if the context relative path
+     *  does not begin with a '/' character
+     * @exception Exception if a different error ocurs
+     */
+    protected URL url(String path) throws Exception
+    {
+
+        if (path.charAt(0) != '/')
+        {
+            throw new IllegalArgumentException("Context path '" + path
+                    + "' does not start with '/'");
+        }
+        return new URL(url, path.substring(1));
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/jmock/AbstractJmockJsfTestCase.java b/test/src/main/java/org/apache/myfaces/test/jmock/AbstractJmockJsfTestCase.java
new file mode 100644
index 0000000..2bd5f95
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/jmock/AbstractJmockJsfTestCase.java
@@ -0,0 +1,354 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.jmock;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import javax.faces.FactoryFinder;
+import javax.faces.application.ApplicationFactory;
+import javax.faces.component.UIViewRoot;
+import javax.faces.lifecycle.LifecycleFactory;
+import javax.faces.render.RenderKitFactory;
+
+import org.apache.myfaces.test.config.ResourceBundleVarNames;
+import org.apache.myfaces.test.mock.MockApplication;
+import org.apache.myfaces.test.mock.MockExternalContext;
+import org.apache.myfaces.test.mock.MockFacesContext;
+import org.apache.myfaces.test.mock.MockFacesContextFactory;
+import org.apache.myfaces.test.mock.MockHttpServletRequest;
+import org.apache.myfaces.test.mock.MockHttpServletResponse;
+import org.apache.myfaces.test.mock.MockHttpSession;
+import org.apache.myfaces.test.mock.MockRenderKit;
+import org.apache.myfaces.test.mock.MockServletConfig;
+import org.apache.myfaces.test.mock.MockServletContext;
+import org.apache.myfaces.test.mock.lifecycle.MockLifecycle;
+import org.apache.myfaces.test.mock.lifecycle.MockLifecycleFactory;
+import org.jmock.cglib.MockObjectTestCase;
+
+/**
+ * <p>Abstract JMock test case base class, which sets up the JavaServer Faces
+ * mock object environment for a particular simulated request.  The following
+ * protected variables are initialized in the <code>setUp()</code> method, and
+ * cleaned up in the <code>tearDown()</code> method:</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>MockHttpServletResponse</code>)</li>
+ * <li><code>servletContext</code> (<code>MockServletContext</code>)</li>
+ * <li><code>session</code> (<code>MockHttpSession</code>)</li>
+ * </ul>
+ *
+ * <p>In addition, appropriate factory classes will have been registered with
+ * <code>javax.faces.FactoryFinder</code> for <code>Application</code> and
+ * <code>RenderKit</code> instances.  The created <code>FacesContext</code>
+ * instance will also have been registered in the proper thread local
+ * variable, to simulate what a servlet container would do.</p>
+ *
+ * <p><strong>WARNING</strong> - If you choose to subclass this class, be sure
+ * your <code>setUp()</code> and <code>tearDown()</code> methods call
+ * <code>super.setUp()</code> and <code>super.tearDown()</code> respectively,
+ * and that you implement your own <code>suite()</code> method that exposes
+ * the test methods for your test case.</p>
+ * 
+ * @since 1.0.0
+ */
+
+public abstract class AbstractJmockJsfTestCase extends MockObjectTestCase
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct a new instance of this test case.</p>
+     *
+     * @param name Name of this test case
+     */
+    public AbstractJmockJsfTestCase(String name)
+    {
+        setName(name);
+    }
+
+    // ---------------------------------------------------- Overall Test Methods
+
+    /**
+     * <p>Set up instance variables required by this test case.</p>
+     */
+    protected void setUp() throws Exception
+    {
+        // Set up a new thread context class loader
+        setUpClassloader();
+
+        // Set up Servlet API Objects
+        setUpServletObjects();
+
+        // Set up JSF API Objects
+        FactoryFinder.releaseFactories();
+
+        setFactories();
+
+        setUpJSFObjects();
+    }
+    
+    /**
+     * Set up the thread context classloader. JSF uses the this classloader
+     * in order to find related factory classes and other resources, but in
+     * some selected cases, the default classloader cannot be properly set.
+     * 
+     * @throws Exception 
+     */
+    protected void setUpClassloader() throws Exception
+    {
+        threadContextClassLoader = Thread.currentThread()
+                .getContextClassLoader();
+        Thread.currentThread()
+                .setContextClassLoader(
+                        new URLClassLoader(new URL[0], this.getClass()
+                                .getClassLoader()));
+        classLoaderSet = true;
+    }
+
+    /**
+     * <p>Setup JSF object used for the test. By default it calls to the following
+     * methods in this order:</p>
+     * 
+     * <ul>
+     * <li><code>setUpExternalContext();</code></li>
+     * <li><code>setUpLifecycle();</code></li>
+     * <li><code>setUpFacesContext();</code></li>
+     * <li><code>setUpView();</code></li>
+     * <li><code>setUpApplication();</code></li>
+     * <li><code>setUpRenderKit();</code></li>
+     * </ul>
+     * 
+     * @throws Exception
+     */
+    protected void setUpJSFObjects() throws Exception
+    {
+        setUpExternalContext();
+        setUpLifecycle();
+        setUpFacesContext();
+        setUpView();
+        setUpApplication();
+        setUpRenderKit();
+    }
+
+    /**
+     * <p>Setup servlet objects that will be used for the test:</p>
+     * 
+     * <ul>
+     * <li><code>config</code> (<code>MockServletConfig</code>)</li>
+     * <li><code>servletContext</code> (<code>MockServletContext</code>)</li>
+     * <li><code>request</code> (<code>MockHttpServletRequest</code></li>
+     * <li><code>response</code> (<code>MockHttpServletResponse</code>)</li>
+     * <li><code>session</code> (<code>MockHttpSession</code>)</li>
+     * </ul>
+     * 
+     * @throws Exception
+     */
+    protected void setUpServletObjects() throws Exception
+    {
+        servletContext = new MockServletContext();
+        config = new MockServletConfig(servletContext);
+        session = new MockHttpSession();
+        session.setServletContext(servletContext);
+        request = new MockHttpServletRequest(session);
+        request.setServletContext(servletContext);
+        response = new MockHttpServletResponse();
+    }
+
+    /**
+     * <p>Set JSF factories using FactoryFinder method setFactory.</p>
+     * 
+     * @throws Exception
+     */
+    protected void setFactories() throws Exception
+    {
+        FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY,
+                "org.apache.myfaces.test.mock.MockApplicationFactory");
+        FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY,
+                "org.apache.myfaces.test.mock.MockFacesContextFactory");
+        FactoryFinder.setFactory(FactoryFinder.LIFECYCLE_FACTORY,
+                "org.apache.myfaces.test.mock.lifecycle.MockLifecycleFactory");
+        FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY,
+                "org.apache.myfaces.test.mock.MockRenderKitFactory");
+        FactoryFinder.setFactory(FactoryFinder.EXCEPTION_HANDLER_FACTORY,
+                "org.apache.myfaces.test.mock.MockExceptionHandlerFactory");
+        FactoryFinder.setFactory(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY,
+                "org.apache.myfaces.test.mock.MockPartialViewContextFactory");
+        FactoryFinder.setFactory(FactoryFinder.VISIT_CONTEXT_FACTORY,
+                "org.apache.myfaces.test.mock.visit.MockVisitContextFactory");
+    }
+
+    /**
+     * Setup the <code>externalContext</code> variable, using the 
+     * servlet variables already initialized.
+     * 
+     * @throws Exception
+     */
+    protected void setUpExternalContext() throws Exception
+    {
+        externalContext = new MockExternalContext(servletContext, request,
+                response);
+    }
+
+    /**
+     * Setup the <code>lifecycle</code> and <code>lifecycleFactory</code>
+     * variables.
+     * 
+     * @throws Exception
+     */
+    protected void setUpLifecycle() throws Exception
+    {
+        lifecycleFactory = (MockLifecycleFactory) FactoryFinder
+                .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
+        lifecycle = (MockLifecycle) lifecycleFactory
+                .getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
+    }
+
+    /**
+     * Setup the <code>facesContextFactory</code> and <code>facesContext</code>
+     * variable. Before end, by default it override <code>externalContext</code>
+     * variable from the value retrieved from facesContext.getExternalContext(),
+     * because sometimes it is possible facesContext overrides externalContext
+     * internally.
+     * 
+     * @throws Exception
+     */
+    protected void setUpFacesContext() throws Exception
+    {
+        facesContextFactory = (MockFacesContextFactory) FactoryFinder
+                .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
+        facesContext = (MockFacesContext) facesContextFactory.getFacesContext(
+                servletContext, request, response, lifecycle);
+        if (facesContext.getExternalContext() != null)
+        {
+            externalContext = (MockExternalContext) facesContext
+                    .getExternalContext();
+        }
+    }
+
+    /**
+     * By default, create an instance of UIViewRoot, set its viewId as "/viewId"
+     * and assign it to the current facesContext.
+     * 
+     * @throws Exception
+     */
+    protected void setUpView() throws Exception
+    {
+        UIViewRoot root = new UIViewRoot();
+        root.setViewId("/viewId");
+        root.setRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT);
+        facesContext.setViewRoot(root);
+    }
+
+    /**
+     * Setup the <code>application</code> variable and before
+     * the end by default it is assigned to the <code>facesContext</code>
+     * variable, calling <code>facesContext.setApplication(application)</code>
+     * 
+     * @throws Exception
+     */
+    protected void setUpApplication() throws Exception
+    {
+        ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder
+                .getFactory(FactoryFinder.APPLICATION_FACTORY);
+        application = (MockApplication) applicationFactory.getApplication();
+        facesContext.setApplication(application);
+    }
+
+    /**
+     * Setup the <code>renderKit</code> variable. This is a good place to use
+     * <code>ConfigParser</code> to register converters, validators, components
+     * or renderkits.
+     * 
+     * @throws Exception
+     */
+    protected void setUpRenderKit() throws Exception
+    {
+        RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder
+                .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+        renderKit = new MockRenderKit();
+        renderKitFactory.addRenderKit(RenderKitFactory.HTML_BASIC_RENDER_KIT,
+                renderKit);
+    }
+
+    /**
+     * <p>Tear down instance variables required by this test case.</p>
+     */
+    protected void tearDown() throws Exception
+    {
+
+        application = null;
+        config = null;
+        externalContext = null;
+        if (facesContext != null)
+        {
+            facesContext.release();
+        }
+        facesContext = null;
+        lifecycle = null;
+        lifecycleFactory = null;
+        renderKit = null;
+        request = null;
+        response = null;
+        servletContext = null;
+        session = null;
+        FactoryFinder.releaseFactories();
+        ResourceBundleVarNames.resetNames();
+
+        tearDownClassloader();
+    }
+    
+    protected void tearDownClassloader() throws Exception
+    {
+        if (classLoaderSet)
+        {
+            Thread.currentThread().setContextClassLoader(threadContextClassLoader);
+            threadContextClassLoader = null;
+            classLoaderSet = false;
+        }
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    // Mock object instances for our tests
+    protected MockApplication application = null;
+    protected MockServletConfig config = null;
+    protected MockExternalContext externalContext = null;
+    protected MockFacesContext facesContext = null;
+    protected MockFacesContextFactory facesContextFactory = null;
+    protected MockLifecycle lifecycle = null;
+    protected MockLifecycleFactory lifecycleFactory = null;
+    protected MockRenderKit renderKit = null;
+    protected MockHttpServletRequest request = null;
+    protected MockHttpServletResponse response = null;
+    protected MockServletContext servletContext = null;
+    protected MockHttpSession session = null;
+
+    // Thread context class loader saved and restored after each test
+    private ClassLoader threadContextClassLoader = null;
+    private boolean classLoaderSet = false;
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/mock/MockActionListener.java b/test/src/main/java/org/apache/myfaces/test/mock/MockActionListener.java
new file mode 100644
index 0000000..3aa9937
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/mock/MockActionListener.java
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.mock;
+
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.ActionEvent;
+import javax.faces.event.ActionListener;
+
+/**
+ * <p>Mock implementation of the default <code>ActionListener</code>.</p>
+ *
+ * $Id$
+ * @since 1.0.0
+ */
+
+public class MockActionListener implements ActionListener
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct a default instance.</p>
+     */
+    public MockActionListener()
+    {
+    }
+
+    // ----------------------------------------------------- Mock Object Methods
+
+    // ------------------------------------------------------ Instance Variables
+
+    // -------------------------------------------------- ActionListener Methods
+
+    /**
+     * <p>Process the specified <code>ActionEvent</code>.</p>
+     *
+     * @param event Event to be processed
+     *
+     * @exception AbortProcessingException if further event firing
+     *  should be skipped
+     */
+    public void processAction(ActionEvent event)
+            throws AbortProcessingException
+    {
+        // FIXME - provide default implementation
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/mock/MockApplication.java b/test/src/main/java/org/apache/myfaces/test/mock/MockApplication.java
new file mode 100644
index 0000000..e32f2a8
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/mock/MockApplication.java
@@ -0,0 +1,407 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.mock;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.faces.FacesException;
+import javax.faces.application.Application;
+import javax.faces.application.NavigationHandler;
+import javax.faces.application.StateManager;
+import javax.faces.application.ViewHandler;
+import javax.faces.component.UIComponent;
+import javax.faces.convert.Converter;
+import javax.faces.event.ActionListener;
+import javax.faces.render.RenderKitFactory;
+import javax.faces.validator.Validator;
+
+/**
+ * <p>Mock implementation of <code>Application</code>.</p>
+ *
+ * $Id$
+ * @since 1.0.0
+ */
+
+public class MockApplication extends Application
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct a default instance.</p>
+     */
+    public MockApplication()
+    {
+
+        setActionListener(new MockActionListener());
+        components = new HashMap();
+        converters = new HashMap();
+        converters1 = new HashMap();
+        setDefaultLocale(Locale.getDefault());
+        setDefaultRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT);
+        setNavigationHandler(new MockNavigationHandler());
+        setStateManager(new MockStateManager());
+        setSupportedLocales(new ArrayList());
+        validators = new HashMap();
+        setViewHandler(new MockViewHandler());
+
+        // Register the standard by-id converters
+        addConverter("javax.faces.BigDecimal",
+                "javax.faces.convert.BigDecimalConverter");
+        addConverter("javax.faces.BigInteger",
+                "javax.faces.convert.BigIntegerConverter");
+        addConverter("javax.faces.Boolean",
+                "javax.faces.convert.BooleanConverter");
+        addConverter("javax.faces.Byte", "javax.faces.convert.ByteConverter");
+        addConverter("javax.faces.Character",
+                "javax.faces.convert.CharacterConverter");
+        addConverter("javax.faces.DateTime",
+                "javax.faces.convert.DateTimeConverter");
+        addConverter("javax.faces.Double",
+                "javax.faces.convert.DoubleConverter");
+        addConverter("javax.faces.Float", "javax.faces.convert.FloatConverter");
+        addConverter("javax.faces.Integer",
+                "javax.faces.Convert.IntegerConverter");
+        addConverter("javax.faces.Long", "javax.faces.convert.LongConverter");
+        addConverter("javax.faces.Number",
+                "javax.faces.convert.NumberConverter");
+        addConverter("javax.faces.Short", "javax.faces.convert.ShortConverter");
+
+        // Register the standard by-type converters
+        addConverter(Boolean.class, "javax.faces.convert.BooleanConverter");
+        addConverter(Boolean.TYPE, "javax.faces.convert.BooleanConverter");
+        addConverter(Byte.class, "javax.faces.convert.ByteConverter");
+        addConverter(Byte.TYPE, "javax.faces.convert.ByteConverter");
+        addConverter(Character.class, "javax.faces.convert.CharacterConverter");
+        addConverter(Character.TYPE, "javax.faces.convert.CharacterConverter");
+        addConverter(Double.class, "javax.faces.convert.DoubleConverter");
+        addConverter(Double.TYPE, "javax.faces.convert.DoubleConverter");
+        addConverter(Float.class, "javax.faces.convert.FloatConverter");
+        addConverter(Float.TYPE, "javax.faces.convert.FloatConverter");
+        addConverter(Integer.class, "javax.faces.convert.IntegerConverter");
+        addConverter(Integer.TYPE, "javax.faces.convert.IntegerConverter");
+        addConverter(Long.class, "javax.faces.convert.LongConverter");
+        addConverter(Long.TYPE, "javax.faces.convert.LongConverter");
+        addConverter(Short.class, "javax.faces.convert.ShortConverter");
+        addConverter(Short.TYPE, "javax.faces.convert.ShortConverter");
+
+    }
+
+    // ----------------------------------------------------- Mock Object Methods
+
+    // ------------------------------------------------------ Instance Variables
+
+    private ActionListener actionListener = null;
+    private Map components = null;
+    private Map converters = null; // By id
+    private Map converters1 = null; // By type
+    private Locale defaultLocale = null;
+    private String defaultRenderKitId = null;
+    private String messageBundle = null;
+    private NavigationHandler navigationHandler = null;
+    private StateManager stateManager = null;
+    private Collection supportedLocales = null;
+    private Map validators = null;
+    private ViewHandler viewHandler = null;
+
+    // ----------------------------------------------------- Application Methods
+
+    /** {@inheritDoc} */
+    public ActionListener getActionListener()
+    {
+
+        return this.actionListener;
+
+    }
+
+    /** {@inheritDoc} */
+    public void setActionListener(ActionListener actionListener)
+    {
+        this.actionListener = actionListener;
+    }
+
+    /** {@inheritDoc} */
+    public Locale getDefaultLocale()
+    {
+
+        return this.defaultLocale;
+
+    }
+
+    /** {@inheritDoc} */
+    public void setDefaultLocale(Locale defaultLocale)
+    {
+
+        this.defaultLocale = defaultLocale;
+
+    }
+
+    /** {@inheritDoc} */
+    public String getDefaultRenderKitId()
+    {
+
+        return this.defaultRenderKitId;
+
+    }
+
+    /** {@inheritDoc} */
+    public void setDefaultRenderKitId(String defaultRenderKitId)
+    {
+
+        this.defaultRenderKitId = defaultRenderKitId;
+
+    }
+
+    /** {@inheritDoc} */
+    public String getMessageBundle()
+    {
+
+        return this.messageBundle;
+
+    }
+
+    /** {@inheritDoc} */
+    public void setMessageBundle(String messageBundle)
+    {
+
+        this.messageBundle = messageBundle;
+
+    }
+
+    /** {@inheritDoc} */
+    public NavigationHandler getNavigationHandler()
+    {
+
+        return this.navigationHandler;
+
+    }
+
+    /** {@inheritDoc} */
+    public void setNavigationHandler(NavigationHandler navigationHandler)
+    {
+
+        this.navigationHandler = navigationHandler;
+
+    }
+
+    /** {@inheritDoc} */
+    public StateManager getStateManager()
+    {
+
+        return this.stateManager;
+
+    }
+
+    /** {@inheritDoc} */
+    public void setStateManager(StateManager stateManager)
+    {
+
+        this.stateManager = stateManager;
+
+    }
+
+    /** {@inheritDoc} */
+    public Iterator getSupportedLocales()
+    {
+
+        return this.supportedLocales.iterator();
+
+    }
+
+    /** {@inheritDoc} */
+    public void setSupportedLocales(Collection supportedLocales)
+    {
+
+        this.supportedLocales = supportedLocales;
+
+    }
+
+    /** {@inheritDoc} */
+    public ViewHandler getViewHandler()
+    {
+
+        return this.viewHandler;
+
+    }
+
+    /** {@inheritDoc} */
+    public void setViewHandler(ViewHandler viewHandler)
+    {
+
+        this.viewHandler = viewHandler;
+
+    }
+
+    /** {@inheritDoc} */
+    public void addComponent(String componentType, String componentClass)
+    {
+
+        components.put(componentType, componentClass);
+
+    }
+
+    /** {@inheritDoc} */
+    public UIComponent createComponent(String componentType)
+    {
+
+        if (componentType == null)
+        {
+            throw new NullPointerException("Requested component type is null");
+        }
+        String componentClass = (String) components.get(componentType);
+        if (componentClass == null)
+        {
+            throw new FacesException(
+                    "No component class registered for component type '"
+                            + componentType + "'");
+        }
+        try
+        {
+            Class clazz = Class.forName(componentClass);
+            return ((UIComponent) clazz.newInstance());
+        }
+        catch (Exception e)
+        {
+            throw new FacesException(e);
+        }
+
+    }
+
+
+    /** {@inheritDoc} */
+    public Iterator getComponentTypes()
+    {
+
+        return (components.keySet().iterator());
+
+    }
+
+    /** {@inheritDoc} */
+    public void addConverter(String converterId, String converterClass)
+    {
+
+        converters.put(converterId, converterClass);
+
+    }
+
+    /** {@inheritDoc} */
+    public void addConverter(Class targetClass, String converterClass)
+    {
+
+        converters1.put(targetClass, converterClass);
+
+    }
+
+    /** {@inheritDoc} */
+    public Converter createConverter(String converterId)
+    {
+
+        String converterClass = (String) converters.get(converterId);
+        if (converterClass == null)
+        {
+            return null;
+        }
+        try
+        {
+            Class clazz = Class.forName(converterClass);
+            return ((Converter) clazz.newInstance());
+        }
+        catch (Exception e)
+        {
+            throw new FacesException(e);
+        }
+
+    }
+
+    /** {@inheritDoc} */
+    public Converter createConverter(Class targetClass)
+    {
+
+        String converterClass = (String) converters1.get(targetClass);
+        if (converterClass == null)
+        {
+            return null;
+        }
+        try
+        {
+            Class clazz = Class.forName(converterClass);
+            return ((Converter) clazz.newInstance());
+        }
+        catch (Exception e)
+        {
+            throw new FacesException(e);
+        }
+
+    }
+
+    /** {@inheritDoc} */
+    public Iterator getConverterIds()
+    {
+
+        return (converters.keySet().iterator());
+
+    }
+
+    /** {@inheritDoc} */
+    public Iterator getConverterTypes()
+    {
+
+        return (converters1.keySet().iterator());
+
+    }
+
+
+    /** {@inheritDoc} */
+    public void addValidator(String validatorId, String validatorClass)
+    {
+
+        validators.put(validatorId, validatorClass);
+
+    }
+
+    /** {@inheritDoc} */
+    public Validator createValidator(String validatorId)
+    {
+
+        String validatorClass = (String) validators.get(validatorId);
+        try
+        {
+            Class clazz = Class.forName(validatorClass);
+            return ((Validator) clazz.newInstance());
+        }
+        catch (Exception e)
+        {
+            throw new FacesException(e);
+        }
+
+    }
+
+    /** {@inheritDoc} */
+    public Iterator getValidatorIds()
+    {
+        return (validators.keySet().iterator());
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/mock/MockApplication12.java b/test/src/main/java/org/apache/myfaces/test/mock/MockApplication12.java
new file mode 100644
index 0000000..d13da73
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/mock/MockApplication12.java
@@ -0,0 +1,307 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.mock;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import javax.el.ArrayELResolver;
+import javax.el.BeanELResolver;
+import javax.el.CompositeELResolver;
+import javax.el.ELContextListener;
+import javax.el.ELException;
+import javax.el.ELResolver;
+import javax.el.ExpressionFactory;
+import javax.el.ListELResolver;
+import javax.el.MapELResolver;
+import javax.el.ResourceBundleELResolver;
+import javax.el.ValueExpression;
+import javax.faces.FacesException;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.test.config.ResourceBundleVarNames;
+import org.apache.myfaces.test.el.FacesImplicitObjectELResolver;
+import org.apache.myfaces.test.el.FacesResourceBundleELResolver;
+import org.apache.myfaces.test.el.FacesScopedAttributeELResolver;
+import org.apache.myfaces.test.el.MockExpressionFactory;
+import org.apache.myfaces.test.el.ReservedWordsELResolver;
+
+/**
+ * <p>Mock implementation of <code>Application</code> that includes the semantics
+ * added by JavaServer Faces 1.2.</p>
+ *
+ * $Id$
+ *
+ * @since 1.0.0
+ */
+public class MockApplication12 extends MockApplication
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct a default instance.</p>
+     */
+    public MockApplication12()
+    {
+
+        super();
+
+        // Configure our expression factory and EL resolvers
+        expressionFactory = new MockExpressionFactory();
+
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>A list of resource bundles configured for this application.</p>
+     */
+    private Map bundles = new HashMap();
+
+    /**
+     * <p>The set of configured ELContextListener instances.</p>
+     */
+    private List elContextListeners = new ArrayList();
+
+    /**
+     * <p>Expression factory for this instance.</p>
+     */
+    private ExpressionFactory expressionFactory = null;
+
+    /**
+     * <p>The configured composite resolver to be returned by <code>getELResolver()</code>.
+     * This value is lazily instantiated.</p>
+     */
+    private ELResolver resolver = null;
+
+    /**
+     * <p>The set of ELResolver instances configured on this instance.</p>
+     */
+    private List resolvers = new ArrayList();
+
+    // ----------------------------------------------------- Mock Object Methods
+
+    /**
+     * <p>Add the specified resource bundle to those associated with
+     * this application.</p>
+     *
+     * @param name Name under which to add this resource bundle
+     * @param bundle ResourceBundle to add
+     */
+    public void addResourceBundle(String name, ResourceBundle bundle)
+    {
+        bundles.put(name, bundle);
+    }
+
+    /**
+     * <p>Return a <code>Map</code> of the resource bundles configured
+     * for this application, keyed by name.</p>
+     */
+    public Map getResourceBundles()
+    {
+        return bundles;
+    }
+
+    /**
+     * Set the current ExpressionFactory to be returned by this mock object
+     * 
+     * @param expressionFactory
+     */
+    public void setExpressionFactory(ExpressionFactory expressionFactory)
+    {
+        this.expressionFactory = expressionFactory;
+    }
+    
+    // ----------------------------------------------------- Application Methods
+
+    /** {@inheritDoc} */
+    public void addELContextListener(ELContextListener listener)
+    {
+
+        elContextListeners.add(listener);
+
+    }
+
+    /** {@inheritDoc} */
+    public void addELResolver(ELResolver resolver)
+    {
+
+        // Simulate the restriction that you cannot add resolvers after
+        // the first request has been processed.
+        if (this.resolver != null)
+        {
+            throw new IllegalStateException("Cannot add resolvers now");
+        }
+
+        resolvers.add(resolver);
+
+    }
+
+    /** {@inheritDoc} */
+    public UIComponent createComponent(ValueExpression expression,
+            FacesContext context, String componentType)
+    {
+
+        UIComponent component = null;
+        try
+        {
+            component = (UIComponent) expression.getValue(context
+                    .getELContext());
+            if (component == null)
+            {
+                component = createComponent(componentType);
+                expression.setValue(context.getELContext(), component);
+            }
+
+        }
+        catch (Exception e)
+        {
+            throw new FacesException(e);
+        }
+        return component;
+
+    }
+
+    /** {@inheritDoc} */
+    public Object evaluateExpressionGet(FacesContext context,
+            String expression, Class expectedType) throws ELException
+    {
+
+        ValueExpression ve = getExpressionFactory().createValueExpression(
+                context.getELContext(), expression, expectedType);
+        return ve.getValue(context.getELContext());
+
+    }
+
+    /** {@inheritDoc} */
+    public ELContextListener[] getELContextListeners()
+    {
+
+        return (ELContextListener[]) elContextListeners
+                .toArray(new ELContextListener[elContextListeners.size()]);
+
+    }
+
+    /** {@inheritDoc} */
+    public ELResolver getELResolver()
+    {
+
+        if (resolver == null)
+        {
+
+            // Configure a default ELResolver per Section 5.6.2 of JSF 1.2
+            CompositeELResolver composite = new CompositeELResolver();
+
+            composite.add(new FacesImplicitObjectELResolver());
+
+            CompositeELResolver nested = new CompositeELResolver();
+            Iterator items = resolvers.iterator();
+            while (items.hasNext())
+            {
+                nested.add((ELResolver) items.next());
+            }
+            composite.add(nested);
+
+            // composite.add(new faces.ManagedBeanELResolver()); // FIXME
+            composite.add(new ResourceBundleELResolver());
+            composite.add(new FacesResourceBundleELResolver());
+            composite.add(new MapELResolver());
+            composite.add(new ListELResolver());
+            composite.add(new ArrayELResolver());
+            composite.add(new BeanELResolver());
+            composite.add(new FacesScopedAttributeELResolver());
+            composite.add(new ReservedWordsELResolver());
+
+            // Make the resolver we have configured the application wide one
+            resolver = composite;
+
+        }
+        return resolver;
+
+    }
+
+    /** {@inheritDoc} */
+    public ExpressionFactory getExpressionFactory()
+    {
+
+        return this.expressionFactory;
+
+    }
+
+    /** {@inheritDoc} */
+    public ResourceBundle getResourceBundle(FacesContext context, String name)
+    {
+
+        if ((context == null) || (name == null))
+        {
+            throw new NullPointerException();
+        }
+        Locale locale = null;
+        UIViewRoot viewRoot = context.getViewRoot();
+        if (viewRoot != null)
+        {
+            locale = viewRoot.getLocale();
+        }
+        if (locale == null)
+        {
+            locale = Locale.getDefault();
+        }
+        try
+        {
+            return ResourceBundle.getBundle(name, locale);
+        }
+        catch (MissingResourceException e)
+        {
+
+            String newName = ResourceBundleVarNames.getVarName(name);
+            if (newName == null)
+            {
+                return null;
+            }
+
+            try
+            {
+                return ResourceBundle.getBundle(newName, locale);
+            }
+            catch (MissingResourceException exc)
+            {
+                return null;
+            }
+
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void removeELContextListener(ELContextListener listener)
+    {
+
+        elContextListeners.remove(listener);
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/mock/MockApplication20.java b/test/src/main/java/org/apache/myfaces/test/mock/MockApplication20.java
new file mode 100644
index 0000000..ad24f1a
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/mock/MockApplication20.java
@@ -0,0 +1,1188 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.mock;
+
+import java.beans.BeanDescriptor;
+import java.beans.BeanInfo;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.el.ELContext;
+import javax.el.ValueExpression;
+import javax.faces.FacesException;
+import javax.faces.application.Application;
+import javax.faces.application.ProjectStage;
+import javax.faces.application.Resource;
+import javax.faces.application.ResourceDependencies;
+import javax.faces.application.ResourceDependency;
+import javax.faces.application.ResourceHandler;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UINamingContainer;
+import javax.faces.component.UIOutput;
+import javax.faces.component.UIViewRoot;
+import javax.faces.component.behavior.Behavior;
+import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.ComponentSystemEventListener;
+import javax.faces.event.ListenerFor;
+import javax.faces.event.ListenersFor;
+import javax.faces.event.SystemEvent;
+import javax.faces.event.SystemEventListener;
+import javax.faces.event.SystemEventListenerHolder;
+import javax.faces.render.Renderer;
+import javax.faces.validator.Validator;
+import javax.faces.view.ViewDeclarationLanguage;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.myfaces.test.mock.resource.MockResourceHandler;
+
+/**
+ * <p>Mock implementation of <code>Application</code> that includes the semantics
+ * added by JavaServer Faces 2.0.</p>
+ * 
+ * @author Leonardo Uribe
+ * @since 1.0.0
+ *
+ */
+public class MockApplication20 extends MockApplication12
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    public MockApplication20()
+    {
+        super();
+
+        // install the 2.0-ViewHandler-Mock
+        this.setViewHandler(new MockViewHandler20());
+        this.setResourceHandler(new MockResourceHandler());
+    }
+
+    private static class SystemListenerEntry
+    {
+        private List<SystemEventListener> _lstSystemEventListener;
+        private Map<Class<?>, List<SystemEventListener>> _sourceClassMap;
+
+        public SystemListenerEntry()
+        {
+        }
+
+        public void addListener(SystemEventListener listener)
+        {
+            assert listener != null;
+
+            addListenerNoDuplicate(getAnySourceListenersNotNull(), listener);
+        }
+
+        public void addListener(SystemEventListener listener, Class<?> source)
+        {
+            assert listener != null;
+
+            if (source == null)
+            {
+                addListener(listener);
+            }
+            else
+            {
+                addListenerNoDuplicate(
+                        getSpecificSourceListenersNotNull(source), listener);
+            }
+        }
+
+        public void removeListener(SystemEventListener listener)
+        {
+            assert listener != null;
+
+            if (_lstSystemEventListener != null)
+            {
+                _lstSystemEventListener.remove(listener);
+            }
+        }
+
+        public void removeListener(SystemEventListener listener,
+                Class<?> sourceClass)
+        {
+            assert listener != null;
+
+            if (sourceClass == null)
+            {
+                removeListener(listener);
+            }
+            else
+            {
+                if (_sourceClassMap != null)
+                {
+                    List<SystemEventListener> listeners = _sourceClassMap
+                            .get(sourceClass);
+                    if (listeners != null)
+                    {
+                        listeners.remove(listener);
+                    }
+                }
+            }
+        }
+
+        public void publish(Class<? extends SystemEvent> systemEventClass,
+                Class<?> classSource, Object source, SystemEvent event)
+        {
+            if (source != null && _sourceClassMap != null)
+            {
+                event = _traverseListenerList(_sourceClassMap.get(classSource),
+                        systemEventClass, source, event);
+            }
+
+            _traverseListenerList(_lstSystemEventListener, systemEventClass,
+                    source, event);
+        }
+
+        private void addListenerNoDuplicate(
+                List<SystemEventListener> listeners,
+                SystemEventListener listener)
+        {
+            if (!listeners.contains(listener))
+            {
+                listeners.add(listener);
+            }
+        }
+
+        private synchronized List<SystemEventListener> getAnySourceListenersNotNull()
+        {
+            if (_lstSystemEventListener == null)
+            {
+                /*
+                 * TODO: Check if modification occurs often or not, might have to use a synchronized list instead.
+                 * 
+                 * Registrations found:
+                 */
+                _lstSystemEventListener = new CopyOnWriteArrayList<SystemEventListener>();
+            }
+
+            return _lstSystemEventListener;
+        }
+
+        private synchronized List<SystemEventListener> getSpecificSourceListenersNotNull(
+                Class<?> sourceClass)
+        {
+            if (_sourceClassMap == null)
+            {
+                _sourceClassMap = new ConcurrentHashMap<Class<?>, List<SystemEventListener>>();
+            }
+
+            List<SystemEventListener> list = _sourceClassMap.get(sourceClass);
+            if (list == null)
+            {
+                /*
+                 * TODO: Check if modification occurs often or not, might have to use a synchronized list instead.
+                 * 
+                 * Registrations found:
+                 */
+                list = new CopyOnWriteArrayList<SystemEventListener>();
+                _sourceClassMap.put(sourceClass, list);
+            }
+
+            return list;
+        }
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    private static final Log log = LogFactory.getLog(MockApplication20.class);
+
+    private final Map<Class<? extends SystemEvent>, SystemListenerEntry> _systemEventListenerClassMap = 
+        new ConcurrentHashMap<Class<? extends SystemEvent>, SystemListenerEntry>();
+
+    private Map<String, String> _defaultValidatorsIds = new HashMap<String, String>();
+
+    private ProjectStage _projectStage;
+
+    private final Map<String, Class<?>> _behaviorClassMap = new ConcurrentHashMap<String, Class<?>>();
+
+    private final Map<String, Class<?>> _validatorClassMap = new ConcurrentHashMap<String, Class<?>>();
+
+    private ResourceHandler _resourceHandler;
+
+    // ----------------------------------------------------- Mock Object Methods
+
+    public Map<String, String> getDefaultValidatorInfo()
+    {
+        return Collections.unmodifiableMap(_defaultValidatorsIds);
+    }
+
+    private void _handleAnnotations(FacesContext context, Object inspected, UIComponent component)
+    {   
+        // determine the ProjectStage setting via the given FacesContext
+        // note that a local getProjectStage() could cause problems in wrapped environments
+        boolean isProduction = context.isProjectStage(ProjectStage.Production);
+        
+        Class<?> inspectedClass = inspected.getClass();
+        _handleListenerForAnnotations(context, inspected, inspectedClass, component, isProduction);
+
+        _handleResourceDependencyAnnotations(context, inspectedClass, component, isProduction);
+    }
+    
+    private void _handleListenerForAnnotations(FacesContext context, Object inspected, Class<?> inspectedClass, 
+        UIComponent component, boolean isProduction)
+    {
+        List<ListenerFor> listenerForList = null;
+        
+        if(listenerForList == null) //not in production or the class hasn't been inspected yet
+        {
+            ListenerFor listener = inspectedClass.getAnnotation(ListenerFor.class);
+            ListenersFor listeners = inspectedClass.getAnnotation(ListenersFor.class);
+            if(listener != null || listeners != null)
+            {
+                //listeners were found using one or both annotations, create and build a new list
+                listenerForList = new ArrayList<ListenerFor>();
+                
+                if(listener != null)
+                {
+                    listenerForList.add(listener);
+                }
+                
+                if(listeners != null)
+                {
+                    listenerForList.addAll(Arrays.asList(listeners.value()));
+                }
+            }
+        }        
+ 
+        if (listenerForList != null) //listeners were found through inspection or from cache, handle them
+        {
+            for (ListenerFor listenerFor : listenerForList)
+            {
+                _handleListenerFor(context, inspected, component, listenerFor);
+            }
+        }
+    }
+
+    private void _handleListenerFor(FacesContext context, Object inspected, UIComponent component,
+                                    ListenerFor annotation)
+    {
+        // If this annotation is not present on the class in question, no action must be taken.
+        if (annotation != null)
+        {
+            // Determine the "target" on which to call subscribeToEvent.
+            // If the class to which this annotation is attached implements ComponentSystemEventListener
+            if (inspected instanceof ComponentSystemEventListener)
+            {
+                // If the class to which this annotation is attached is a UIComponent instance, "target" is the
+                // UIComponent instance.
+
+                // If the class to which this annotation is attached is a Renderer instance, "target" is the
+                // UIComponent instance.
+
+                /*
+                 * If "target" is a UIComponent call UIComponent.subscribeToEvent(Class, ComponentSystemEventListener)
+                 * passing the systemEventClass() of the annotation as the first argument and the instance of the class
+                 * to which this annotation is attached (which must implement ComponentSystemEventListener) as the
+                 * second argument.
+                 */
+                component.subscribeToEvent(annotation.systemEventClass(), (ComponentSystemEventListener) inspected);
+            }
+            // If the class to which this annotation is attached implements SystemEventListener and does not implement
+            // ComponentSystemEventListener, "target" is the Application instance.
+            else if (component instanceof SystemEventListener)
+            {
+                // use the Application object from the FacesContext (note that a
+                // direct use of subscribeToEvent() could cause problems if the
+                // Application is wrapped)
+                Application application = context.getApplication();
+                
+                // If "target" is the Application instance, inspect the value of the sourceClass() annotation attribute
+                // value.
+                if (Void.class.equals(annotation.sourceClass()))
+                {
+                    /*
+                     * If the value is Void.class, call Application.subscribeToEvent(Class, SystemEventListener),
+                     * passing the value of systemEventClass() as the first argument and the instance of the class to
+                     * which this annotation is attached (which must implement SystemEventListener) as the second
+                     * argument.
+                     */
+                    application.subscribeToEvent(annotation.systemEventClass(), (SystemEventListener) inspected);
+                }
+                else
+                {
+                    /*
+                     * Otherwise, call Application.subscribeToEvent(Class, Class, SystemEventListener), passing the
+                     * value of systemEventClass() as the first argument, the value of sourceClass() as the second
+                     * argument, and the instance of the class to which this annotation is attached (which must
+                     * implement SystemEventListener) as the third argument.
+                     */
+                    application.subscribeToEvent(annotation.systemEventClass(), annotation.sourceClass(),
+                                     (SystemEventListener) inspected);
+                }
+            }
+
+            /*
+             * If the class to which this annotation is attached implements ComponentSystemEventListener and is neither
+             * an instance of Renderer nor UIComponent, the action taken is unspecified. This case must not trigger any
+             * kind of error.
+             */
+        }
+    }
+
+    private void _handleResourceDependencyAnnotations(FacesContext context, Class<?> inspectedClass, 
+        UIComponent component, boolean isProduction)
+    {
+        List<ResourceDependency> dependencyList = null;
+        
+        if(dependencyList == null)  //not in production or the class hasn't been inspected yet
+        {   
+            ResourceDependency dependency = inspectedClass.getAnnotation(ResourceDependency.class);
+            ResourceDependencies dependencies = inspectedClass.getAnnotation(ResourceDependencies.class);
+            if(dependency != null || dependencies != null)
+            {
+                //resource dependencies were found using one or both annotations, create and build a new list
+                dependencyList = new ArrayList<ResourceDependency>();
+                
+                if(dependency != null)
+                {
+                    dependencyList.add(dependency);
+                }
+                
+                if(dependencies != null)
+                {
+                    dependencyList.addAll(Arrays.asList(dependencies.value()));
+                }
+            }
+        }        
+ 
+        if (dependencyList != null) //resource dependencies were found through inspection or from cache, handle them
+        {
+            for (ResourceDependency dependency : dependencyList)
+            {
+                _handleResourceDependency(context, component, dependency);
+            }
+        }
+    }
+    
+    private void _handleResourceDependency(FacesContext context, UIComponent component, ResourceDependency annotation)
+    {
+        // If this annotation is not present on the class in question, no action must be taken.
+        if (annotation != null)
+        {
+            // Create a UIOutput instance by passing javax.faces.Output. to
+            // Application.createComponent(java.lang.String).
+            UIOutput output = (UIOutput) createComponent(UIOutput.COMPONENT_TYPE);
+
+            // Get the annotation instance from the class and obtain the values of the name, library, and
+            // target attributes.
+            String name = annotation.name();
+            if (name != null && name.length() > 0)
+            {
+                name = _ELText.parse(getExpressionFactory(), context.getELContext(), name).toString(
+                    context.getELContext());
+            }
+
+            // Obtain the renderer-type for the resource name by passing name to
+            // ResourceHandler.getRendererTypeForResourceName(java.lang.String).
+            // (note that we can not use this.getResourceHandler(), because the Application might be wrapped)
+            String rendererType = context.getApplication().getResourceHandler().getRendererTypeForResourceName(name);
+
+            // Call setRendererType on the UIOutput instance, passing the renderer-type.
+            output.setRendererType(rendererType);
+
+            // Obtain the Map of attributes from the UIOutput component by calling UIComponent.getAttributes().
+            Map<String, Object> attributes = output.getAttributes();
+
+            // Store the name into the attributes Map under the key "name".
+            attributes.put("name", name);
+
+            // If library is the empty string, let library be null.
+            String library = annotation.library();
+            if (library != null && library.length() > 0)
+            {
+                library = _ELText.parse(getExpressionFactory(), context.getELContext(), library).toString(
+                    context.getELContext());
+                // If library is non-null, store it under the key "library".
+                if ("this".equals(library))
+                {
+                    // Special "this" behavior
+                    Resource resource = (Resource)component.getAttributes().get(Resource.COMPONENT_RESOURCE_KEY);
+                    if (resource != null)
+                    {
+                        attributes.put("library", resource.getLibraryName());
+                    }
+                }
+                else
+                {
+                    attributes.put("library", library);
+                }
+            }
+
+            // If target is the empty string, let target be null.
+            String target = annotation.target();
+            if (target != null && target.length() > 0)
+            {
+                target = _ELText.parse(getExpressionFactory(), context.getELContext(), target).toString(
+                    context.getELContext());
+                // If target is non-null, store it under the key "target".
+                attributes.put("target", target);
+                context.getViewRoot().addComponentResource(context, output, target);
+            }
+            else
+            {
+                // Otherwise, if target is null, call UIViewRoot.addComponentResource(javax.faces.context.FacesContext,
+                // javax.faces.component.UIComponent), passing the UIOutput instance as the second argument.
+                context.getViewRoot().addComponentResource(context, output);
+            }
+        }
+    }
+    
+    private void _inspectRenderer(FacesContext context, UIComponent component, String componentType,
+        String rendererType)
+    {
+        /*
+         * The Renderer instance to inspect must be obtained by calling FacesContext.getRenderKit() and calling
+         * RenderKit.getRenderer(java.lang.String, java.lang.String) on the result, passing the argument componentFamily
+         * of the newly created component as the first argument and the argument rendererType as the second argument.
+         */
+        Renderer renderer = context.getRenderKit().getRenderer(component.getFamily(), rendererType);
+        if (renderer == null)
+        {
+            // If no such Renderer can be found, a message must be logged with a helpful error message.
+            log.error("renderer cannot be found for component type " + componentType + " and renderer type "
+                    + rendererType);
+        }
+        else
+        {
+            // Otherwise, UIComponent.setRendererType(java.lang.String) must be called on the newly created
+            // UIComponent instance, passing the argument rendererType as the argument.
+            component.setRendererType(rendererType);
+
+            /*
+             * except the Renderer for the component to be returned must be inspected for the annotations mentioned in
+             * createComponent(ValueExpression, FacesContext, String) as specified in the documentation for that method.
+             */
+            _handleAnnotations(context, renderer, component);
+        }
+    }
+    
+    private static SystemEvent _traverseListenerList(
+            List<? extends SystemEventListener> listeners,
+            Class<? extends SystemEvent> systemEventClass, Object source,
+            SystemEvent event)
+    {
+        if (listeners != null && !listeners.isEmpty())
+        {
+            for (SystemEventListener listener : listeners)
+            {
+                // Call SystemEventListener.isListenerForSource(java.lang.Object), passing the source argument.
+                // If this returns false, take no action on the listener.
+                if (listener.isListenerForSource(source))
+                {
+                    // Otherwise, if the event to be passed to the listener instances has not yet been constructed,
+                    // construct the event, passing source as the argument to the one-argument constructor that takes
+                    // an Object. This same event instance must be passed to all listener instances.
+                    event = _createEvent(systemEventClass, source, event);
+
+                    // Call SystemEvent.isAppropriateListener(javax.faces.event.FacesListener), passing the listener
+                    // instance as the argument. If this returns false, take no action on the listener.
+                    if (event.isAppropriateListener(listener))
+                    {
+                        // Call SystemEvent.processListener(javax.faces.event.FacesListener), passing the listener
+                        // instance.
+                        event.processListener(listener);
+                    }
+                }
+            }
+        }
+
+        return event;
+    }
+
+    private static SystemEvent _createEvent(
+            Class<? extends SystemEvent> systemEventClass, Object source,
+            SystemEvent event)
+    {
+        if (event == null)
+        {
+            try
+            {
+                Constructor<?>[] constructors = systemEventClass.getConstructors();
+                Constructor<? extends SystemEvent> constructor = null;
+                for (Constructor<?> c : constructors)
+                {
+                    if (c.getParameterTypes().length == 1)
+                    {
+                        // Safe cast, since the constructor belongs
+                        // to a class of type SystemEvent
+                        constructor = (Constructor<? extends SystemEvent>) c;
+                        break;
+                    }
+                }
+                if (constructor != null)
+                {
+                    event = constructor.newInstance(source);
+                }
+
+            }
+            catch (Exception e)
+            {
+                throw new FacesException("Couldn't instanciate system event of type " + systemEventClass.getName(), e);
+            }
+        }
+
+        return event;
+    }
+
+    private void checkNull(final Object param, final String paramName)
+    {
+        if (param == null)
+        {
+            throw new NullPointerException(paramName + " cannot be null.");
+        }
+    }
+
+    private void checkEmpty(final String param, final String paramName)
+    {
+        if (param.length() == 0)
+        {
+            throw new NullPointerException("String " + paramName
+                    + " cannot be empty.");
+        }
+    }
+
+    public void publishEvent(FacesContext facesContext,
+            Class<? extends SystemEvent> systemEventClass,
+            Class<?> sourceBaseType, Object source)
+    {
+        checkNull(systemEventClass, "systemEventClass");
+        checkNull(source, "source");
+        
+        //Call events only if event processing is enabled.
+        if (!facesContext.isProcessingEvents())
+        {
+            return;
+        }
+
+        try
+        {
+            SystemEvent event = null;
+            if (source instanceof SystemEventListenerHolder)
+            {
+                SystemEventListenerHolder holder = (SystemEventListenerHolder) source;
+
+                // If the source argument implements SystemEventListenerHolder, call 
+                // SystemEventListenerHolder.getListenersForEventClass(java.lang.Class) on it, 
+                // passing the systemEventClass 
+                // argument. If the list is not empty, perform algorithm traverseListenerList on the list.
+                event = _traverseListenerList(holder
+                        .getListenersForEventClass(systemEventClass),
+                        systemEventClass, source, event);
+            }
+            
+            UIViewRoot uiViewRoot = facesContext.getViewRoot();
+            if (uiViewRoot != null)
+            {
+                //Call listeners on view level
+                event = _traverseListenerList(uiViewRoot.getViewListenersForEventClass(systemEventClass), 
+                        systemEventClass, source, event);
+            }
+
+            SystemListenerEntry systemListenerEntry = _systemEventListenerClassMap
+                    .get(systemEventClass);
+            if (systemListenerEntry != null)
+            {
+                systemListenerEntry.publish(systemEventClass, sourceBaseType,
+                        source, event);
+            }
+        }
+        catch (AbortProcessingException e)
+        {
+            // If the act of invoking the processListener method causes an AbortProcessingException to be thrown, 
+            // processing of the listeners must be aborted, no further processing of the listeners for this event must 
+            // take place, and the exception must be logged with Level.SEVERE.
+            log.error("Event processing was aborted", e);
+        }
+    }
+
+    public void publishEvent(FacesContext facesContext,
+            Class<? extends SystemEvent> systemEventClass, Object source)
+    {
+        publishEvent(facesContext, systemEventClass, source.getClass(), source);
+    }
+
+    public ProjectStage getProjectStage()
+    {
+        // If the value has already been determined by a previous call to this
+        // method, simply return that value.
+        if (_projectStage == null)
+        {
+
+            FacesContext context = FacesContext.getCurrentInstance();
+            String stageName = context.getExternalContext().getInitParameter(
+                    ProjectStage.PROJECT_STAGE_PARAM_NAME);
+
+            // If a value is found found
+            if (stageName != null)
+            {
+                /*
+                 * see if an enum constant can be obtained by calling ProjectStage.valueOf(), passing the value from the
+                 * initParamMap. If this succeeds without exception, save the value and return it.
+                 */
+                try
+                {
+                    _projectStage = ProjectStage.valueOf(stageName);
+                    return _projectStage;
+                }
+                catch (IllegalArgumentException e)
+                {
+                    //log.log(Level.SEVERE, "Couldn't discover the current project stage", e);
+                }
+            }
+
+            _projectStage = ProjectStage.Production;
+        }
+
+        return _projectStage;
+    }
+
+    public void addBehavior(String behaviorId, String behaviorClass)
+    {
+        checkNull(behaviorId, "behaviorId");
+        checkEmpty(behaviorId, "behaviorId");
+        checkNull(behaviorClass, "behaviorClass");
+        checkEmpty(behaviorClass, "behaviorClass");
+
+        try
+        {
+            _behaviorClassMap.put(behaviorId, Class.forName(behaviorClass));
+        }
+        catch (ClassNotFoundException ignore)
+        {
+
+        }
+
+    }
+
+    public Iterator<String> getBehaviorIds()
+    {
+        return _behaviorClassMap.keySet().iterator();
+    }
+
+    public Behavior createBehavior(String behaviorId) throws FacesException
+    {
+        checkNull(behaviorId, "behaviorId");
+        checkEmpty(behaviorId, "behaviorId");
+
+        final Class<?> behaviorClass = this._behaviorClassMap.get(behaviorId);
+        if (behaviorClass == null)
+        {
+            throw new FacesException(
+                    "Could not find any registered behavior-class for behaviorId : "
+                            + behaviorId);
+        }
+
+        try
+        {
+            final Behavior behavior = (Behavior) behaviorClass.newInstance();
+            _handleAttachedResourceDependencyAnnotations(FacesContext.getCurrentInstance(), behaviorClass);            
+            return behavior;
+        }
+        catch (Exception e)
+        {
+            throw new FacesException("Could not instantiate behavior: "
+                    + behaviorClass, e);
+        }
+    }
+
+    @Override
+    public void addValidator(String validatorId, String validatorClass)
+    {
+        super.addValidator(validatorId, validatorClass);
+
+        try
+        {
+            _validatorClassMap.put(validatorId, Class.forName(validatorClass));
+        }
+        catch (ClassNotFoundException ex)
+        {
+            throw new FacesException(ex.getMessage());
+        }
+
+    }
+
+    public void addDefaultValidatorId(String validatorId)
+    {
+        if (_validatorClassMap.containsKey(validatorId))
+        {
+            _defaultValidatorsIds.put(validatorId, _validatorClassMap.get(
+                    validatorId).getName());
+        }
+    }
+
+    public final ResourceHandler getResourceHandler()
+    {
+        return _resourceHandler;
+    }
+
+    public final void setResourceHandler(ResourceHandler resourceHandler)
+    {
+        checkNull(resourceHandler, "resourceHandler");
+
+        _resourceHandler = resourceHandler;
+    }
+
+    public void subscribeToEvent(Class<? extends SystemEvent> systemEventClass,
+            SystemEventListener listener)
+    {
+        subscribeToEvent(systemEventClass, null, listener);
+    }
+
+    public void subscribeToEvent(Class<? extends SystemEvent> systemEventClass,
+            Class<?> sourceClass, SystemEventListener listener)
+    {
+        checkNull(systemEventClass, "systemEventClass");
+        checkNull(listener, "listener");
+
+        SystemListenerEntry systemListenerEntry;
+        synchronized (_systemEventListenerClassMap)
+        {
+            systemListenerEntry = _systemEventListenerClassMap
+                    .get(systemEventClass);
+            if (systemListenerEntry == null)
+            {
+                systemListenerEntry = new SystemListenerEntry();
+                _systemEventListenerClassMap.put(systemEventClass,
+                        systemListenerEntry);
+            }
+        }
+
+        systemListenerEntry.addListener(listener, sourceClass);
+    }
+
+    public void unsubscribeFromEvent(
+            Class<? extends SystemEvent> systemEventClass,
+            SystemEventListener listener)
+    {
+        unsubscribeFromEvent(systemEventClass, null, listener);
+    }
+
+    public void unsubscribeFromEvent(
+            Class<? extends SystemEvent> systemEventClass,
+            Class<?> sourceClass, SystemEventListener listener)
+    {
+        checkNull(systemEventClass, "systemEventClass");
+        checkNull(listener, "listener");
+
+        SystemListenerEntry systemListenerEntry = _systemEventListenerClassMap
+                .get(systemEventClass);
+        if (systemListenerEntry != null)
+        {
+            systemListenerEntry.removeListener(listener, sourceClass);
+        }
+    }
+
+    @Override
+    public UIComponent createComponent(String componentType)
+    {
+        UIComponent component = super.createComponent(componentType);
+        _handleAnnotations(FacesContext.getCurrentInstance(), component, component);
+        return component;
+    }
+    
+
+    @Override
+    public UIComponent createComponent(ValueExpression componentExpression,
+                                       FacesContext facesContext, String componentType)
+            throws FacesException, NullPointerException
+    {
+
+        /*
+         * Before the component instance is returned, it must be inspected for the presence of a ListenerFor (or
+         * ListenersFor) or ResourceDependency (or ResourceDependencies) annotation. If any of these annotations are
+         * present, the action listed in ListenerFor or ResourceDependency must be taken on the component, before it is
+         * returned from this method. This variant of createComponent must not inspect the Renderer for the component to
+         * be returned for any of the afore mentioned annotations. Such inspection is the province of
+         */
+
+        checkNull(componentExpression, "componentExpression");
+        checkNull(facesContext, "facesContext");
+        checkNull(componentType, "componentType");
+
+        ELContext elContext = facesContext.getELContext();
+
+        try
+        {
+            Object retVal = componentExpression.getValue(elContext);
+
+            UIComponent createdComponent;
+
+            if (retVal instanceof UIComponent)
+            {
+                createdComponent = (UIComponent) retVal;
+                _handleAnnotations(facesContext, createdComponent, createdComponent);
+            }
+            else
+            {
+                createdComponent = createComponent(componentType);
+                componentExpression.setValue(elContext, createdComponent);
+            }
+
+            return createdComponent;
+        }
+        catch (FacesException e)
+        {
+            throw e;
+        }
+        catch (Exception e)
+        {
+            throw new FacesException(e);
+        }
+    }
+
+    @Override
+    public UIComponent createComponent(ValueExpression componentExpression, FacesContext context, String componentType,
+                                       String rendererType)
+    {
+        // Like createComponent(ValueExpression, FacesContext, String)
+        UIComponent component = createComponent(componentExpression, context, componentType);
+
+        _inspectRenderer(context, component, componentType, rendererType);
+
+        return component;
+    }
+    
+
+    @Override
+    public UIComponent createComponent(FacesContext context, String componentType, String rendererType)
+    {
+        checkNull(context, "context");
+        checkNull(componentType, "componentType");
+
+        // Like createComponent(String)
+        UIComponent component = createComponent(componentType);
+
+        _inspectRenderer(context, component, componentType, rendererType);
+
+        return component;
+    }
+
+    @Override
+    public UIComponent createComponent(FacesContext context, Resource componentResource)
+    {
+        checkNull(context, "context");
+        checkNull(componentResource, "componentResource");
+        
+        UIComponent component = null;
+        Resource resource;
+        String fqcn;
+        Class<? extends UIComponent> componentClass = null;
+
+        /*
+         * Obtain a reference to the ViewDeclarationLanguage for this Application instance by calling
+         * ViewHandler.getViewDeclarationLanguage(javax.faces.context.FacesContext, java.lang.String), passing the
+         * viewId found by calling UIViewRoot.getViewId() on the UIViewRoot in the argument FacesContext.
+         */
+        UIViewRoot view = context.getViewRoot();
+        Application application = context.getApplication();
+        ViewDeclarationLanguage vdl = application.getViewHandler().getViewDeclarationLanguage(
+            context, view.getViewId());
+
+        /*
+         * Obtain a reference to the composite component metadata for this composite component by calling
+         * ViewDeclarationLanguage.getComponentMetadata(javax.faces.context.FacesContext,
+         * javax.faces.application.Resource), passing the facesContext and componentResource arguments to this method.
+         * This version of JSF specification uses JavaBeans as the API to the component metadata.
+         */
+        BeanInfo metadata = vdl.getComponentMetadata(context, componentResource);
+        if (metadata == null)
+        {
+            throw new FacesException("Could not get component metadata for " 
+                    + componentResource.getResourceName()
+                    + ". Did you forget to specify <composite:interface>?");
+        }
+
+        /*
+         * Determine if the component author declared a component-type for this component instance by obtaining the
+         * BeanDescriptor from the component metadata and calling its getValue() method, passing
+         * UIComponent.COMPOSITE_COMPONENT_TYPE_KEY as the argument. If non-null, the result must be a ValueExpression
+         * whose value is the component-type of the UIComponent to be created for this Resource component. Call through
+         * to createComponent(java.lang.String) to create the component.
+         */
+        BeanDescriptor descriptor = metadata.getBeanDescriptor();
+        ValueExpression componentType = (ValueExpression) descriptor.getValue(UIComponent.COMPOSITE_COMPONENT_TYPE_KEY);
+        boolean annotationsApplied = false;
+        if (componentType != null)
+        {
+            component = application.createComponent((String) componentType.getValue(context.getELContext()));
+            annotationsApplied = true;
+        }
+        else
+        {
+            /*
+             * Otherwise, determine if a script based component for this Resource can be found by calling
+             * ViewDeclarationLanguage.getScriptComponentResource(javax.faces.context.FacesContext,
+             * javax.faces.application.Resource). If the result is non-null, and is a script written in one of the
+             * languages listed in JSF 4.3 of the specification prose document, create a UIComponent instance from the
+             * script resource.
+             */
+            resource = vdl.getScriptComponentResource(context, componentResource);
+            if (resource != null)
+            {
+                String name = resource.getResourceName();
+                String className = name.substring(0, name.lastIndexOf('.'));
+                
+                Class clazz;
+                try
+                {
+                    clazz = Class.forName(className);
+                    component = (UIComponent)clazz.newInstance();
+                }
+                catch (Exception e)
+                {
+                    throw new FacesException(e);
+                }
+            }
+            else
+            {
+                /*
+                 * Otherwise, let library-name be the return from calling Resource.getLibraryName() on the argument
+                 * componentResource and resource-name be the return from calling Resource.getResourceName() on the
+                 * argument componentResource. Create a fully qualified Java class name by removing any file extension
+                 * from resource-name and let fqcn be library-name + "." + resource-name. If a class with the name of
+                 * fqcn cannot be found, take no action and continue to the next step. If any of InstantiationException,
+                 * IllegalAccessException, or ClassCastException are thrown, wrap the exception in a FacesException and
+                 * re-throw it. If any other exception is thrown, log the exception and continue to the next step.
+                 */
+
+                String name = componentResource.getResourceName();
+                String className = name.substring(0, name.lastIndexOf('.'));
+                fqcn = componentResource.getLibraryName() + "." + className;
+                
+                try
+                {
+                    componentClass = classForName(fqcn);
+                }
+                catch (ClassNotFoundException e)
+                {
+                }
+
+                if (componentClass != null)
+                {
+                    try
+                    {
+                        component = componentClass.newInstance();
+                    }
+                    catch (InstantiationException e)
+                    {
+                        log.error("Could not instantiate component class name = " + fqcn, e);
+                        throw new FacesException("Could not instantiate component class name = " + fqcn, e);
+                    }
+                    catch (IllegalAccessException e)
+                    {
+                        log.error("Could not instantiate component class name = " + fqcn, e);
+                        throw new FacesException("Could not instantiate component class name = " + fqcn, e);
+                    }
+                    catch (Exception e)
+                    {
+                        log.error("Could not instantiate component class name = " + fqcn, e);
+                    }
+                }
+
+                /*
+                 * If none of the previous steps have yielded a UIComponent instance, call
+                 * createComponent(java.lang.String) passing "javax.faces.NamingContainer" as the argument.
+                 */
+                if (component == null)
+                {
+                    component = application.createComponent(UINamingContainer.COMPONENT_TYPE);
+                    annotationsApplied = true;
+                }
+            }
+        }
+
+        /*
+         * Call UIComponent.setRendererType(java.lang.String) on the UIComponent instance, passing
+         * "javax.faces.Composite" as the argument.
+         */
+        component.setRendererType("javax.faces.Composite");
+
+        /*
+         * Store the argument Resource in the attributes Map of the UIComponent under the key,
+         * Resource.COMPONENT_RESOURCE_KEY.
+         */
+        component.getAttributes().put(Resource.COMPONENT_RESOURCE_KEY, componentResource);
+
+        /*
+         * Store composite component metadata in the attributes Map of the UIComponent under the key,
+         * UIComponent.BEANINFO_KEY.
+         */
+        component.getAttributes().put(UIComponent.BEANINFO_KEY, metadata);
+
+        /*
+         * Before the component instance is returned, it must be inspected for the presence of a ListenerFor annotation.
+         * If this annotation is present, the action listed in ListenerFor must be taken on the component, before it is
+         * returned from this method.
+         */
+        if (!annotationsApplied)
+        {
+            _handleAnnotations(context, component, component);
+        }
+
+        return component;
+    }
+    
+    private static Class classForName(String type)
+        throws ClassNotFoundException
+    {
+        if (type == null)
+        {
+            throw new NullPointerException("type");
+        }
+        try
+        {
+            // Try WebApp ClassLoader first
+            return Class.forName(type,
+                                 false, // do not initialize for faster startup
+                                 Thread.currentThread().getContextClassLoader());
+        }
+        catch (ClassNotFoundException ignore)
+        {
+            // fallback: Try ClassLoader for ClassUtils (i.e. the myfaces.jar lib)
+            return Class.forName(type,
+                                 false, // do not initialize for faster startup
+                                 MockApplication20.class.getClassLoader());
+        }
+    }
+    
+    private void _handleAttachedResourceDependencyAnnotations(FacesContext context, Object inspected)
+    {
+        if (inspected == null)
+        {
+            return;
+        }
+        
+        ResourceDependency annotation = inspected.getClass().getAnnotation(ResourceDependency.class);
+        
+        if (annotation == null)
+        {
+            // If the ResourceDependency annotation is not present, the argument must be inspected for the presence 
+            // of the ResourceDependencies annotation. 
+            ResourceDependencies dependencies = inspected.getClass().getAnnotation(ResourceDependencies.class);
+            if (dependencies != null)
+            {
+                // If the ResourceDependencies annotation is present, the action described in ResourceDependencies 
+                // must be taken.
+                for (ResourceDependency dependency : dependencies.value())
+                {
+                    _handleAttachedResourceDependency(context, dependency);
+                }
+            }
+        }
+        else
+        {
+            // If the ResourceDependency annotation is present, the action described in ResourceDependency must be 
+            // taken. 
+            _handleAttachedResourceDependency(context, annotation);
+        }
+    }
+    
+    private void _handleAttachedResourceDependency(FacesContext context, ResourceDependency annotation)
+    {
+        // If this annotation is not present on the class in question, no action must be taken. 
+        if (annotation != null)
+        {
+            Application application = context.getApplication();
+            
+            // Create a UIOutput instance by passing javax.faces.Output. to 
+            // Application.createComponent(java.lang.String).
+            UIOutput output = (UIOutput) application.createComponent(UIOutput.COMPONENT_TYPE);
+            
+            // Get the annotation instance from the class and obtain the values of the name, library, and 
+            // target attributes.
+            String name = annotation.name();
+            if (name != null && name.length() > 0)
+            {
+                name = _ELText.parse(getExpressionFactory(), context.getELContext(), name).toString(
+                    context.getELContext());
+            }
+            
+            // Obtain the renderer-type for the resource name by passing name to 
+            // ResourceHandler.getRendererTypeForResourceName(java.lang.String).
+            String rendererType = application.getResourceHandler().getRendererTypeForResourceName(name);
+            
+            // Call setRendererType on the UIOutput instance, passing the renderer-type.
+            output.setRendererType(rendererType);
+            
+            // Obtain the Map of attributes from the UIOutput component by calling UIComponent.getAttributes().
+            Map<String, Object> attributes = output.getAttributes();
+            
+            // Store the name into the attributes Map under the key "name".
+            attributes.put("name", name);
+            
+            // If library is the empty string, let library be null.
+            String library = annotation.library();
+            if (library != null && library.length() > 0)
+            {
+                library = _ELText.parse(getExpressionFactory(), context.getELContext(), library).toString(
+                    context.getELContext());
+                // If library is non-null, store it under the key "library".
+                attributes.put("library", library);
+            }
+            
+            // If target is the empty string, let target be null.
+            String target = annotation.target();
+            if (target != null && target.length() > 0)
+            {
+                target = _ELText.parse(getExpressionFactory(), context.getELContext(), target).toString(
+                    context.getELContext());
+                // If target is non-null, store it under the key "target".
+                attributes.put("target", target);
+                context.getViewRoot().addComponentResource(context, output, target);
+            }
+            else
+            {
+                // Otherwise, if target is null, call UIViewRoot.addComponentResource(javax.faces.context.FacesContext, 
+                // javax.faces.component.UIComponent), passing the UIOutput instance as the second argument.
+                context.getViewRoot().addComponentResource(context, output);
+            }
+        }
+    }
+
+    @Override
+    public Converter createConverter(String converterId)
+    {
+        Converter converter = super.createConverter(converterId);
+        _handleAttachedResourceDependencyAnnotations(FacesContext.getCurrentInstance(), converter);
+        return converter;
+    }
+
+    @Override
+    public Validator createValidator(String validatorId)
+    {
+        Validator validator = super.createValidator(validatorId);
+        _handleAttachedResourceDependencyAnnotations(FacesContext.getCurrentInstance(), validator);
+        return validator;
+    }
+    
+    
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/mock/MockApplication22.java b/test/src/main/java/org/apache/myfaces/test/mock/MockApplication22.java
new file mode 100644
index 0000000..68dc315
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/mock/MockApplication22.java
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.mock;
+
+import javax.faces.flow.FlowHandler;
+
+/**
+ * <p>Mock implementation of <code>Application</code> that includes the semantics
+ * added by JavaServer Faces 2.0.</p>
+ * 
+ * @author Leonardo Uribe
+ * @since 1.0.0
+ *
+ */
+public class MockApplication22 extends MockApplication20
+{
+    // ------------------------------------------------------------ Constructors
+
+    public MockApplication22()
+    {
+        super();
+
+        // install flow Handler
+        setFlowHandler(new MockFlowHandler());
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    private FlowHandler _flowHandler;
+
+    // ----------------------------------------------------- Mock Object Methods
+
+    @Override
+    public FlowHandler getFlowHandler()
+    {
+        return _flowHandler;
+    }
+
+    @Override
+    public void setFlowHandler(FlowHandler flowHandler)
+    {
+        this._flowHandler = flowHandler;
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/mock/MockApplication30.java b/test/src/main/java/org/apache/myfaces/test/mock/MockApplication30.java
new file mode 100644
index 0000000..382c8f0
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/mock/MockApplication30.java
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.mock;
+
+import javax.faces.flow.FlowHandler;
+
+/**
+ * <p>Mock implementation of <code>Application</code> that includes the semantics
+ * added by JavaServer Faces 3.0.</p>
+ * 
+ * @author Leonardo Uribe
+ * @since 1.0.0
+ *
+ */
+public class MockApplication30 extends MockApplication22
+{
+    // ------------------------------------------------------------ Constructors
+
+    public MockApplication30()
+    {
+        super();
+
+        // install flow Handler
+        setFlowHandler(new MockFlowHandler());
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    private FlowHandler _flowHandler;
+
+    // ----------------------------------------------------- Mock Object Methods
+
+    @Override
+    public FlowHandler getFlowHandler()
+    {
+        return _flowHandler;
+    }
+
+    @Override
+    public void setFlowHandler(FlowHandler flowHandler)
+    {
+        this._flowHandler = flowHandler;
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/mock/MockApplicationFactory.java b/test/src/main/java/org/apache/myfaces/test/mock/MockApplicationFactory.java
new file mode 100644
index 0000000..9a76fdd
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/mock/MockApplicationFactory.java
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.mock;
+
+import javax.faces.FacesException;
+import javax.faces.application.Application;
+import javax.faces.application.ApplicationFactory;
+
+/**
+ * <p>Mock implementation of <code>ApplicationFactory</code>.</p>
+ *
+ * $Id$
+ * @since 1.0.0
+ */
+
+public class MockApplicationFactory extends ApplicationFactory
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct a default instance.</p>
+     */
+    public MockApplicationFactory()
+    {
+
+    }
+
+    // ----------------------------------------------------- Mock Object Methods
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>The <code>Application</code> instance to be returned by
+     * this factory.</p>
+     */
+    private Application application = null;
+
+    // --------------------------------------------- AppolicationFactory Methods
+
+    /** {@inheritDoc} */
+    public Application getApplication()
+    {
+
+        if (this.application == null)
+        {
+            Class clazz = null;
+
+            try
+            {
+                clazz = this.getClass().getClassLoader().loadClass(
+                        "org.apache.myfaces.test.mock.MockApplication22");
+                if (clazz == null)
+                {
+                    clazz = this.getClass().getClassLoader().loadClass(
+                            "org.apache.myfaces.test.mock.MockApplication20");
+                }
+                this.application = (MockApplication) clazz.newInstance();
+            }
+            catch (NoClassDefFoundError e)
+            {
+                clazz = null; // We are not running in a JSF 1.2 environment
+            }
+            catch (ClassNotFoundException e)
+            {
+                clazz = null; // Same as above
+            }
+            catch (RuntimeException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new FacesException(e);
+            }
+
+            if (clazz == null)
+            {
+                try
+                {
+                    clazz = this.getClass().getClassLoader().loadClass(
+                            "org.apache.myfaces.test.mock.MockApplication12");
+                    this.application = (MockApplication) clazz.newInstance();
+                }
+                catch (NoClassDefFoundError e)
+                {
+                    clazz = null; // We are not running in a JSF 1.2 environment
+                }
+                catch (ClassNotFoundException e)
+                {
+                    clazz = null; // Same as above
+                }
+                catch (RuntimeException e)
+                {
+                    throw e;
+                }
+                catch (Exception e)
+                {
+                    throw new FacesException(e);
+                }
+            }
+            if (clazz == null)
+            {
+                try
+                {
+                    clazz = this.getClass().getClassLoader().loadClass(
+                            "org.apache.myfaces.test.mock.MockApplication");
+                    this.application = (MockApplication) clazz.newInstance();
+                }
+                catch (RuntimeException e)
+                {
+                    throw e;
+                }
+                catch (Exception e)
+                {
+                    throw new FacesException(e);
+                }
+            }
+        }
+        return this.application;
+
+    }
+
+    /** {@inheritDoc} */
+    public void setApplication(Application application)
+    {
+
+        this.application = application;
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/mock/MockClientWindow.java b/test/src/main/java/org/apache/myfaces/test/mock/MockClientWindow.java
new file mode 100644
index 0000000..4c2b539
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/mock/MockClientWindow.java
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+package org.apache.myfaces.test.mock;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.faces.context.FacesContext;
+import javax.faces.lifecycle.ClientWindow;
+import javax.faces.render.ResponseStateManager;
+
+/**
+ * Mock ClientWindow implementation that by default set the id with "1".
+ * 
+ * @author Leonardo Uribe
+ */
+public class MockClientWindow extends ClientWindow
+{
+    private String windowId;
+    
+    private Map<String,String> queryParamsMap;
+
+    public MockClientWindow()
+    {
+    }
+    
+    @Override
+    public void decode(FacesContext context)
+    {
+        String windowId = calculateWindowId(context);
+
+        if (windowId != null)
+        {
+            // Store the current windowId.
+            setId(windowId);
+        }
+        else
+        {
+            //Generate a new windowId
+            setId("1");
+        }
+    }
+    
+    
+    protected String calculateWindowId(FacesContext context)
+    {
+        //1. If it comes as parameter, it takes precedence over any other choice, because
+        //   no browser is capable to do a POST and create a new window at the same time.
+        String windowId = context.getExternalContext().getRequestParameterMap().get(
+                ResponseStateManager.CLIENT_WINDOW_PARAM);
+        if (windowId != null)
+        {
+            return windowId;
+        }
+        windowId = context.getExternalContext().getRequestParameterMap().get(
+                ResponseStateManager.CLIENT_WINDOW_URL_PARAM);
+        if (windowId != null)
+        {
+            return windowId;
+        }
+        return null;
+    }
+
+    @Override
+    public String getId()
+    {
+        return this.windowId;
+    }
+    
+    public void setId(String id)
+    {
+        this.windowId = id;
+    }
+
+    @Override
+    public Map<String, String> getQueryURLParameters(FacesContext context)
+    {
+        if (queryParamsMap == null)
+        {
+            String id = context.getExternalContext().getClientWindow().getId();
+            if (id != null)
+            {
+                queryParamsMap = new HashMap<String, String>(2,1);
+                queryParamsMap.put(ResponseStateManager.CLIENT_WINDOW_URL_PARAM, id);
+            }
+        }
+        return queryParamsMap;
+    }
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/mock/MockClientWindowFactory.java b/test/src/main/java/org/apache/myfaces/test/mock/MockClientWindowFactory.java
new file mode 100644
index 0000000..6e57e32
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/mock/MockClientWindowFactory.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+package org.apache.myfaces.test.mock;
+
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.lifecycle.ClientWindow;
+import javax.faces.lifecycle.ClientWindowFactory;
+
+/**
+ *
+ * @author lu4242
+ */
+public class MockClientWindowFactory extends ClientWindowFactory
+{
+    private static final String WINDOW_MODE_NONE = "none";
+    private static final String WINDOW_MODE_MOCK = "mock";
+    
+    private String windowMode;
+
+    @Override
+    public ClientWindow getClientWindow(FacesContext facesContext)
+    {
+        if (WINDOW_MODE_NONE.equals(getWindowMode(facesContext)))
+        {
+            //No need to do anything
+            return null;
+        }
+        else
+        {
+            if (WINDOW_MODE_MOCK.equals(getWindowMode(facesContext)))
+            {
+                return new MockClientWindow();
+            }
+            else
+            {
+                return null;
+            }
+        }
+    }    
+    
+    private String getWindowMode(FacesContext context)
+    {
+        if (windowMode == null)
+        {
+            windowMode = getStringInitParameter(
+                    context.getExternalContext(), 
+                    ClientWindow.CLIENT_WINDOW_MODE_PARAM_NAME, WINDOW_MODE_NONE);
+        }
+        return windowMode;
+    }
+    
+    private static String getStringInitParameter(ExternalContext context, String name, String defaultValue)
+    {
+        if (name == null)
+        {
+            throw new NullPointerException();
+        }
+        
+        String param = context.getInitParameter(name);
+        
+        if (param == null)
+        {
+            return defaultValue;
+        }
+
+        param = param.trim();
+        if (param.length() == 0)
+        {
+            return defaultValue;
+        }
+
+        return param;
+    }    
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/mock/MockEnumeration.java b/test/src/main/java/org/apache/myfaces/test/mock/MockEnumeration.java
new file mode 100644
index 0000000..ea452e8
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/mock/MockEnumeration.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.mock;
+
+import java.util.Enumeration;
+import java.util.Iterator;
+
+/**
+ * <p>Mock implementation of an <code>Enumeration</code> wrapper around
+ * an <code>Iterator</code>.</p>
+ *
+ * $Id$
+ * @since 1.0.0
+ */
+
+class MockEnumeration implements Enumeration
+{
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct a wrapper instance.</p>
+     *
+     * @param iterator The <code>Iterator</code> to be wrapped
+     */
+    public MockEnumeration(Iterator iterator)
+    {
+
+        this.iterator = iterator;
+
+    }
+
+    // ----------------------------------------------------- Mock Object Methods
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>The <code>Iterator</code> we are wrapping.</p>
+     */
+    private Iterator iterator;
+
+    // ----------------------------------------------------- Enumeration Methods
+
+    /** {@inheritDoc} */
+    public boolean hasMoreElements()
+    {
+
+        return iterator.hasNext();
+
+    }
+
+    /** {@inheritDoc} */
+    public Object nextElement()
+    {
+
+        return iterator.next();
+
+    }
+
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/mock/MockExceptionHandler.java b/test/src/main/java/org/apache/myfaces/test/mock/MockExceptionHandler.java
new file mode 100644
index 0000000..2e7a0c0
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/mock/MockExceptionHandler.java
@@ -0,0 +1,220 @@
+/*
+ * 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.
+ */
+package org.apache.myfaces.test.mock;
+
+import javax.el.ELException;
+import javax.faces.FacesException;
+import javax.faces.context.ExceptionHandler;
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.ExceptionQueuedEvent;
+import javax.faces.event.ExceptionQueuedEventContext;
+import javax.faces.event.SystemEvent;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.Queue;
+
+/**
+ * <p>Mock implementation of <code>ExceptionHandler</code>.</p>
+ * <p/>
+ * $Id$
+ *
+ * @since 1.0.0
+ */
+public class MockExceptionHandler extends ExceptionHandler
+{
+
+    private Queue<ExceptionQueuedEvent> handled;
+    private Queue<ExceptionQueuedEvent> unhandled;
+    private ExceptionQueuedEvent handledAndThrown;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ExceptionQueuedEvent getHandledExceptionQueuedEvent()
+    {
+        return handledAndThrown;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Iterable<ExceptionQueuedEvent> getHandledExceptionQueuedEvents()
+    {
+        return handled == null ? Collections.<ExceptionQueuedEvent> emptyList()
+                : handled;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Throwable getRootCause(Throwable t)
+    {
+        if (t == null)
+        {
+            throw new NullPointerException("t");
+        }
+
+        while (t != null)
+        {
+            Class<?> clazz = t.getClass();
+            if (!clazz.equals(FacesException.class)
+                    && !clazz.equals(ELException.class))
+            {
+                return t;
+            }
+
+            t = t.getCause();
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Iterable<ExceptionQueuedEvent> getUnhandledExceptionQueuedEvents()
+    {
+        return unhandled == null ? Collections
+                .<ExceptionQueuedEvent> emptyList() : unhandled;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handle() throws FacesException
+    {
+        if (unhandled != null && !unhandled.isEmpty())
+        {
+            if (handled == null)
+            {
+                handled = new LinkedList<ExceptionQueuedEvent>();
+            }
+
+            FacesException toThrow = null;
+
+            do
+            {
+                // For each ExceptionEvent in the list
+
+                // get the event to handle
+                ExceptionQueuedEvent event = unhandled.peek();
+                try
+                {
+                    // call its getContext() method
+                    ExceptionQueuedEventContext context = event.getContext();
+
+                    // and call getException() on the returned result
+                    Throwable exception = context.getException();
+
+                    // Upon encountering the first such Exception that is not an instance of
+                    // javax.faces.event.AbortProcessingException
+                    if (!shouldSkip(exception))
+                    {
+                        // set handledAndThrown so that getHandledExceptionQueuedEvent() returns this event
+                        handledAndThrown = event;
+
+                        // Re-wrap toThrow in a ServletException or (PortletException, if in a portlet environment)
+                        // and throw it
+                        // FIXME: The spec says to NOT use a FacesException to propagate the exception, but I see
+                        //        no other way as ServletException is not a RuntimeException
+                        toThrow = wrap(getRethrownException(exception));
+                        break;
+                    }
+                }
+                catch (Throwable t)
+                {
+                    // A FacesException must be thrown if a problem occurs while performing
+                    // the algorithm to handle the exception
+                    throw new FacesException(
+                            "Could not perform the algorithm to handle the Exception",
+                            t);
+                }
+                finally
+                {
+                    // if we will throw the Exception or if we just logged it,
+                    // we handled it in either way --> add to handled
+                    handled.add(event);
+                    unhandled.remove(event);
+                }
+            } while (!unhandled.isEmpty());
+
+            // do we have to throw an Exception?
+            if (toThrow != null)
+            {
+                throw toThrow;
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isListenerForSource(Object source)
+    {
+        return source instanceof ExceptionQueuedEventContext;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void processEvent(SystemEvent exceptionQueuedEvent)
+            throws AbortProcessingException
+    {
+        if (unhandled == null)
+        {
+            unhandled = new LinkedList<ExceptionQueuedEvent>();
+        }
+
+        unhandled.add((ExceptionQueuedEvent) exceptionQueuedEvent);
+    }
+
+    protected Throwable getRethrownException(Throwable exception)
+    {
+        // Let toRethrow be either the result of calling getRootCause() on the Exception,
+        // or the Exception itself, whichever is non-null
+        Throwable toRethrow = getRootCause(exception);
+        if (toRethrow == null)
+        {
+            toRethrow = exception;
+        }
+
+        return toRethrow;
+    }
+
+    protected FacesException wrap(Throwable exception)
+    {
+        if (exception instanceof FacesException)
+        {
+            return (FacesException) exception;
+        }
+        return new FacesException(exception);
+    }
+
+    protected boolean shouldSkip(Throwable exception)
+    {
+        return exception instanceof AbortProcessingException;
+    }
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/mock/MockExceptionHandlerFactory.java b/test/src/main/java/org/apache/myfaces/test/mock/MockExceptionHandlerFactory.java
new file mode 100644
index 0000000..8072d1f
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/mock/MockExceptionHandlerFactory.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+package org.apache.myfaces.test.mock;
+
+import javax.faces.context.ExceptionHandler;
+import javax.faces.context.ExceptionHandlerFactory;
+
+/**
+ * <p>Mock implementation of <code>ExceptionHandlerFactory</code>.</p>
+ * <p/>
+ * $Id$
+ *
+ * @since 1.0.0
+ */
+public class MockExceptionHandlerFactory extends ExceptionHandlerFactory
+{
+
+    @Override
+    public ExceptionHandler getExceptionHandler()
+    {
+        return new MockExceptionHandler();
+    }
+}
diff --git a/test/src/main/java/org/apache/myfaces/test/mock/MockExternalContext.java b/test/src/main/java/org/apache/myfaces/test/mock/MockExternalContext.java
new file mode 100644
index 0000000..1774fa0
--- /dev/null
+++ b/test/src/main/java/org/apache/myfaces/test/mock/MockExternalContext.java
@@ -0,0 +1,540 @@
+/*
+ * 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
+ *
... 18230 lines suppressed ...