JSFUnit with Apache Myfaces Orchestra
ruado Aug 28, 2010 4:09 AMOver the last few days, I have tried to use JSFUnit to test a Orchestra-based web application. It worked fine when I tested pages which only used Conversation Manual Scope Bean. However, things went wrong when I tested pages associated with Conversation Access Scope Bean. The root cause I got was:
Caused by: java.lang.IllegalArgumentException: Orchestra was unable to create an instance of bean with name 'AccessScopeManager'. Ensure that JSF variable resolution uses your dependency injection (DI) framework (eg Spring's DelegatingVariableResolver is in your faces-config.xml file) and the standard Orchestra configuration beans are defined (eg by using <import resource="classpath*:/META-INF/spring-orchestra-init.xml" />). at org.apache.myfaces.orchestra.conversation.AccessScopeManager.getInstance(AccessScopeManager.java:98) at org.apache.myfaces.orchestra.conversation.ConversationAccessLifetimeAspect.markAsAccessed(ConversationAccessLifetimeAspect.java:35) at org.apache.myfaces.orchestra.conversation.spring.SpringConversationScope.notifyAccessConversation(SpringConversationScope.java:197) at org.apache.myfaces.orchestra.conversation.spring.AbstractSpringOrchestraScope.getRealBean(AbstractSpringOrchestraScope.java:366) at org.apache.myfaces.orchestra.conversation.spring.ScopedBeanTargetSource.getTarget(ScopedBeanTargetSource.java:76) at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.getTarget(Cglib2AopProxy.java:657) at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:608) at vn.csp.duchoa.webmodule.model.ManageUnitTypeBackingBean$EnhancerByCGLIB$39e14763.getData(<generated>) ... 56 more
After a couple of days trying to debug and searching for a workaround, I have found out a solution. I start this discussion to share with other people who may come across this problem.
The workaround is to follow the installation guide available at : http://myfaces.apache.org/orchestra/myfaces-orchestra-core/installation.html . However, instead of using
org.apache.myfaces.orchestra.frameworkAdapter.basic.BasicFrameworkAdapterFilter
, you should use
org.apache.myfaces.orchestra.frameworkAdapter.jsf.JsfFrameworkAdapterFilter
This is because while JsfFrameworkAdapterFilter creates JsfFrameworkAdapter which use a VariableResolver instance to search for a required bean, BasicFrameworkAdapterFilter creates BasicFrameworkAdapter which only search for a particular bean in request or session scope. Moreover, when an Access Scope bean is accessed, Orchestra will mark the current Conversation accessed by calling this method :
org.apache.myfaces.orchestra.conversation.ConversationAccessLifetimeAspect.markAsAccessed()
This method in turn get the AccessScopeManager instance by calling
org.apache.myfaces.orchestra.conversation.AccessScopeManager.getInstance()
Take a look at the code inside method getInstance(), you can see that it calls FrameworkAdapter.getBean(String name) to get the AccessScopeManager. If JsfFrameworkAdapter is used, it can create a AccessScopeManager instance because AccessScopeManager bean is configured as a request scope bean in Orchestra's Spring configuration file. On the other hand, exception will be thrown if BasicFrameworkAdapter is used because BasicFrameworkAdapter instance can only get bean instances in the request or session scope.
Here is a fragment of web.xml to enable you test Orchestra-based web application with JSFUnit:
... <filter> <filter-name>frameworkAdapterFilter</filter-name> <filter-class>org.apache.myfaces.orchestra.frameworkAdapter.jsf.JsfFrameworkAdapterFilter</filter-class> </filter> <filter> <filter-name>requestParameterFilter</filter-name> <filter-class>org.apache.myfaces.orchestra.requestParameterProvider.RequestParameterServletFilter</filter-class> </filter> <filter> <filter-name>JSFUnitFilter</filter-name> <filter-class>org.jboss.jsfunit.framework.JSFUnitFilter</filter-class> </filter> <filter-mapping> <filter-name>frameworkAdapterFilter</filter-name> <servlet-name>ServletRedirector</servlet-name> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping> <filter-mapping> <filter-name>requestParameterFilter</filter-name> <servlet-name>ServletRedirector</servlet-name> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping> <filter-mapping> <filter-name>JSFUnitFilter</filter-name> <servlet-name>ServletTestRunner</servlet-name> </filter-mapping> <filter-mapping> <filter-name>JSFUnitFilter</filter-name> <servlet-name>ServletRedirector</servlet-name> </filter-mapping> <servlet> <servlet-name>ServletRedirector</servlet-name> <servlet-class>org.apache.cactus.server.ServletTestRedirector</servlet-class> </servlet> <servlet> <servlet-name>ServletTestRunner</servlet-name> <servlet-class>org.apache.cactus.server.runner.ServletTestRunner</servlet-class> </servlet> <servlet-mapping> <servlet-name>ServletRedirector</servlet-name> <url-pattern>/ServletRedirector</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>ServletTestRunner</servlet-name> <url-pattern>/ServletTestRunner</url-pattern> </servlet-mapping> ...