Seam Integration Test Problem
fastnsilver Oct 2, 2008 9:23 PMFirst the environment...
WinXP SP2, Eclipse 3.4, JBossTools, Seam 2.0.2.SP1, Spring 2.0.7, RichFaces 3.2.2.GA, Tomcat 6.0.18, Ant 1.7, TestNG.
I'm trying to run a Seam integration test.
Caveats: 1) jboss-embedded jars not in the classpath and 2) a non seam-gen structured project. I reference this article and this forum post for proof that such a config can work.
My bean under test depends on Spring to inject a command.
Here's the test...
public class LoginBeanTestNGTest extends SeamTest{ private Command<LoginResult, LoginAction> loginCommand; @BeforeTest public void createLoginCommand() { loginCommand = new Command<LoginResult, LoginAction>(){ public ResponseToken<LoginResult> execute(LoginAction action) { ResponseToken<LoginResult> response = new ApplicationResponseToken<LoginResult>(); LoginResult result = new LoginResult(); response.setResult(result); return response; } }; } @Test public void login() throws Exception{ new FacesRequest("/login.xhtml") { @Override protected void updateModelValues() { setValue("#{identity.username}", "qa-ramyac"); setValue("#{identity.password}", "expeditors"); } @Override protected void invokeApplication() { setValue("#{loginBean.loginCommand}", loginCommand); boolean isLoginSuccess = new Boolean(invokeMethod("#{loginBean.login}").toString()); assert isLoginSuccess; } }.run(); } }
Here's the bean...
@Name("loginBean") @Scope(ScopeType.SESSION) public class LoginBean implements LoginAction, Serializable { private String username; private String password; @In(required=false) FacesMessages facesMessages; @In(value="#{loginCommand}") private Command<LoginResult, LoginAction> loginCommand; @In(value="#{logoutCommand}") private Command<Void, Action> logoutCommand; public boolean login(){ this.username = Identity.instance().getUsername(); this.password = Identity.instance().getPassword(); ResponseToken<LoginResult> response = this.loginCommand.execute(this); if(response.isSuccessful()){ LoginResult loginResult = response.getResult(); if(null == loginResult) { return false; } return true; } else { facesMessages = ResponseTokenTranslator.getFacesMessagesFromResponse(response, MessageTranslator.getMessage("login_invalid")); Identity.instance().setUsername(null); Identity.instance().setPassword(null); return false; } } public void logout() { ResponseToken<Void> response = this.logoutCommand.execute(null); } public String getUsername() { return username; } public String getPassword() { return password; } }
Note the injection. These Spring bean commands are indeed defined in the application context.
Here's the kicker, a snippet of the exception...
[testng] FAILED: login [testng] java.lang.AssertionError: javax.el.PropertyNotFoundException: Property 'loginCommand' not found on type com.expd.app.tar.login.backing.LoginBean_$$_javassist_11 [testng] at org.jboss.seam.mock.BaseSeamTest$Request.onException(BaseSeamTest.java:488) [testng] at org.jboss.seam.mock.BaseSeamTest$Request$2.doFilter(BaseSeamTest.java:537) [testng] at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83) [testng] at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:85) [testng] at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [testng] at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64) [testng] at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [testng] at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45) [testng] at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [testng] at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:177) [testng] at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:267) [testng] at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:380) [testng] at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:507) [testng] at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:60) [testng] at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [testng] at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:58) [testng] at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [testng] at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158) [testng] at org.jboss.seam.mock.BaseSeamTest$Request.run(BaseSeamTest.java:524) [testng] at com.expd.app.tar.login.backing.LoginBeanTestNGTest.login(LoginBeanTestNGTest.java:48) [testng] Caused by: javax.el.PropertyNotFoundException: Property 'loginCommand' not found on type com.expd.app.tar.login.backing.LoginBean_$$_javassist_11 [testng] at javax.el.BeanELResolver$BeanProperties.get(BeanELResolver.java:193) [testng] at javax.el.BeanELResolver$BeanProperties.access$400(BeanELResolver.java:170) [testng] at javax.el.BeanELResolver.property(BeanELResolver.java:279) [testng] at javax.el.BeanELResolver.setValue(BeanELResolver.java:106) [testng] at javax.el.CompositeELResolver.setValue(CompositeELResolver.java:68) [testng] at javax.el.CompositeELResolver.setValue(CompositeELResolver.java:68) [testng] at org.jboss.el.parser.AstPropertySuffix.setValue(AstPropertySuffix.java:73) [testng] at org.jboss.el.parser.AstValue.setValue(AstValue.java:84) [testng] at org.jboss.el.ValueExpressionImpl.setValue(ValueExpressionImpl.java:249) [testng] at org.jboss.seam.mock.BaseSeamTest$Request.setValue(BaseSeamTest.java:463) [testng] at com.expd.app.tar.login.backing.LoginBeanTestNGTest$2.invokeApplication(LoginBeanTestNGTest.java:59) [testng] at org.jboss.seam.mock.BaseSeamTest$Request.invokeApplicationPhase(BaseSeamTest.java:660) [testng] at org.jboss.seam.mock.BaseSeamTest$Request.emulateJsfLifecycle(BaseSeamTest.java:609) [testng] at org.jboss.seam.mock.BaseSeamTest$Request.access$300(BaseSeamTest.java:184) [testng] at org.jboss.seam.mock.BaseSeamTest$Request$2.doFilter(BaseSeamTest.java:530) [testng] ... 40 more [testng] ... Removed 22 stack frames
Just before this exception in the debug output I see stuff that makes me nervous like...
[testng] 2008-10-01 17:39:05,401 INFO *main* DefaultListableBeanFactory.destroySingletons:282 [] Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@7d2796: defining beans [userProfileDataProvider,userProfileDataFactory,userProfileBusinessProvider,userProfileBusinessFactory,versionReader,adminSessionProvider,accessControlStrategy,authenticationStrategy,authorizationStrategy,securityService,dataSource,entityManagerFactorySpring,entityManagerFactory,txManager,org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor,loginCommand,logoutCommand,eulaSignedCommand,forcedLoginCommand,passwordForceChangedCommand,isAuthenticatedCommand,isSessionExpiredCommand,reportDefinitionLookupStrategy,searchSubmissionStrategy,summarySearchSubmissionStrategy,searchCommand,emailReportCommand,summaryCommand,metaDataCommand,referenceTabCommand,searchDetailsCommand,promptCommand,platformProfile]; root of factory hierarchy [testng] 2008-10-01 17:39:05,401 INFO *main* SeamManagedEntityManagerFactoryBean.destroy:340 [] Closing JPA EntityManagerFactory for persistence unit 'tartest:seam' [testng] 2008-10-01 17:39:05,401 INFO *main* LocalContainerEntityManagerFactoryBean.destroy:340 [] Closing JPA EntityManagerFactory for persistence unit 'tartest' [testng] 2008-10-01 17:39:05,417 INFO *main* SessionFactoryImpl.close:769 [] closing [testng] 2008-10-01 17:39:05,417 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.ioc.spring.springELResolver [testng] 2008-10-01 17:39:05,417 DEBUG *main* Component.newInstance:1965 [] instantiating Seam component: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,417 DEBUG *main* Component.initialize:1385 [] initializing new instance of: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,417 DEBUG *main* Component.initialize:1402 [] done initializing: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,417 DEBUG *main* Component.newInstance:1965 [] instantiating Seam component: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,417 DEBUG *main* Component.initialize:1385 [] initializing new instance of: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,417 DEBUG *main* Component.initialize:1402 [] done initializing: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,417 DEBUG *main* Events.raiseEvent:61 [] Processing event:org.jboss.seam.preDestroy.org.jboss.seam.ioc.spring.springELResolver [testng] 2008-10-01 17:39:05,433 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.framework.currentTime.component [testng] 2008-10-01 17:39:05,433 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.captcha.captchaImage.component [testng] 2008-10-01 17:39:05,433 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.core.init.component [testng] 2008-10-01 17:39:05,433 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.faces.renderer.component [testng] 2008-10-01 17:39:05,433 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.international.messagesFactory.component [testng] 2008-10-01 17:39:05,433 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.ui.hibernateEntityLoader.component [testng] 2008-10-01 17:39:05,433 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.core.conversation.component [testng] 2008-10-01 17:39:05,433 DEBUG *main* Contexts.destroy:244 [] destroying: promptBean.component [testng] 2008-10-01 17:39:05,433 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.security.identity.component [testng] 2008-10-01 17:39:05,433 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.core.ConversationIdGenerator.component [testng] 2008-10-01 17:39:05,448 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.core.conversationEntries.component [testng] 2008-10-01 17:39:05,448 DEBUG *main* Contexts.destroy:244 [] destroying: eulaBean.component [testng] 2008-10-01 17:39:05,448 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.international.timeZoneSelector.component [testng] 2008-10-01 17:39:05,448 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.ui.entityIdentifierStore.component [testng] 2008-10-01 17:39:05,448 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.faces.validation.component [testng] 2008-10-01 17:39:05,448 DEBUG *main* Contexts.destroy:244 [] destroying: org.springframework.web.context.WebApplicationContext.ROOT [testng] 2008-10-01 17:39:05,448 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.core.expressions.component [testng] 2008-10-01 17:39:05,448 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.faces.facesContext.component [testng] 2008-10-01 17:39:05,448 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.transaction.transaction.component [testng] 2008-10-01 17:39:05,448 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.web.ajax4jsfFilter.component [testng] 2008-10-01 17:39:05,448 DEBUG *main* Contexts.destroy:244 [] destroying: envBean [testng] 2008-10-01 17:39:05,448 DEBUG *main* Component.newInstance:1965 [] instantiating Seam component: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,448 DEBUG *main* Component.initialize:1385 [] initializing new instance of: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,448 DEBUG *main* Component.initialize:1402 [] done initializing: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,464 DEBUG *main* Component.newInstance:1965 [] instantiating Seam component: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,464 DEBUG *main* Component.initialize:1385 [] initializing new instance of: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,464 DEBUG *main* Component.initialize:1402 [] done initializing: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,464 DEBUG *main* Events.raiseEvent:61 [] Processing event:org.jboss.seam.preDestroy.envBean [testng] 2008-10-01 17:39:05,464 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.mail.mailSession.component [testng] 2008-10-01 17:39:05,464 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.faces.uiComponent.component [testng] 2008-10-01 17:39:05,464 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.core.contexts.component [testng] 2008-10-01 17:39:05,480 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.security.facesSecurityEvents.component [testng] 2008-10-01 17:39:05,480 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.core.expressions [testng] 2008-10-01 17:39:05,480 DEBUG *main* Component.newInstance:1965 [] instantiating Seam component: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,480 DEBUG *main* Component.initialize:1385 [] initializing new instance of: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,480 DEBUG *main* Component.initialize:1402 [] done initializing: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,480 DEBUG *main* Component.newInstance:1965 [] instantiating Seam component: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,480 DEBUG *main* Component.initialize:1385 [] initializing new instance of: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,480 DEBUG *main* Component.initialize:1402 [] done initializing: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,480 DEBUG *main* Events.raiseEvent:61 [] Processing event:org.jboss.seam.preDestroy.org.jboss.seam.core.expressions [testng] 2008-10-01 17:39:05,480 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.web.loggingFilter.component [testng] 2008-10-01 17:39:05,480 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.core.init [testng] 2008-10-01 17:39:05,495 DEBUG *main* Component.newInstance:1965 [] instantiating Seam component: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,495 DEBUG *main* Component.initialize:1385 [] initializing new instance of: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,495 DEBUG *main* Component.initialize:1402 [] done initializing: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,495 DEBUG *main* Component.newInstance:1965 [] instantiating Seam component: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,495 DEBUG *main* Component.initialize:1385 [] initializing new instance of: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,495 DEBUG *main* Component.initialize:1402 [] done initializing: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,495 DEBUG *main* Events.raiseEvent:61 [] Processing event:org.jboss.seam.preDestroy.org.jboss.seam.core.init [testng] 2008-10-01 17:39:05,495 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.ui.resource.safeStyleResources.component [testng] 2008-10-01 17:39:05,495 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.core.locale.component [testng] 2008-10-01 17:39:05,495 DEBUG *main* Contexts.destroy:244 [] destroying: org.jboss.seam.core.resourceBundle.component [testng] 2008-10-01 17:39:05,495 DEBUG *main* Component.newInstance:1965 [] instantiating Seam component: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,495 DEBUG *main* Component.initialize:1385 [] initializing new instance of: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,495 DEBUG *main* Component.initialize:1402 [] done initializing: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,495 DEBUG *main* Component.newInstance:1965 [] instantiating Seam component: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,495 DEBUG *main* Component.initialize:1385 [] initializing new instance of: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,511 DEBUG *main* Component.initialize:1402 [] done initializing: org.jboss.seam.core.events [testng] 2008-10-01 17:39:05,511 DEBUG *main* Events.raiseEvent:61 [] Processing event:org.jboss.seam.postDestroyContext.APPLICATION
Seems like stuff the test needs to run is getting destroyed before it can make use of it.
I am happy to provide any additional information you may need to help me successfully troubleshoot this issue (e.g., web.xml, components.xml, faces-config.xml, other source if that will help).
I will say a few things more...
Where I work we have a rigid project structure and build policy. We use Ant to build, deploy and run our app and tests. And we do not use EJBs. Therefore, we go to the trouble of configuring Seam with Spring managed transactions deployed on Tomcat. Simply falling back on a seam-gen project structure is not an option.
Here's the project structure...
C:\development\workspaces\rp\tar>ls -la total 249 drwxr-xr-x+ 15 4294967295 mkpasswd 0 Oct 1 17:37 . drwxr-xr-x+ 19 4294967295 mkpasswd 0 Sep 24 14:00 .. -rwxr-xr-x 1 4294967295 mkpasswd 1030 Oct 1 16:48 .classpath -rwxr-xr-x 1 4294967295 mkpasswd 67 Jul 7 16:23 .cvsignore -rwxr-xr-x 1 4294967295 mkpasswd 873 Sep 25 16:07 .project drwxr-xr-x+ 3 4294967295 mkpasswd 0 Sep 26 09:17 .settings -rwxr-xr-x 1 4294967295 mkpasswd 158720 Oct 5 2007 BuildHowTo_ReleaseNotes-2_0_0.doc drwxr-xr-x+ 2 4294967295 mkpasswd 0 Sep 23 16:30 CVS -rwxr-xr-x 1 4294967295 mkpasswd 0 Aug 29 15:41 DO_METRICS drwxr-xr-x+ 3 4294967295 mkpasswd 0 Oct 1 16:24 archive drwxr-xr-x+ 10 4294967295 mkpasswd 0 Oct 1 16:25 build -rwxr-xr-x 1 4294967295 mkpasswd 4534 Jul 11 14:32 build.properties -rwxr-xr-x 1 4294967295 mkpasswd 73917 Oct 1 16:36 build.xml drwxr-xr-x+ 6 4294967295 mkpasswd 0 Sep 23 16:30 codegen drwxr-xr-x+ 7 4294967295 mkpasswd 0 Oct 1 17:37 dist drwxr-xr-x+ 7 4294967295 mkpasswd 0 Sep 23 16:29 doc drwxr-xr-x+ 3 4294967295 mkpasswd 0 Sep 23 16:29 fitTest drwxr-xr-x+ 2 4294967295 mkpasswd 0 Oct 1 17:38 logs drwxr-xr-x+ 4 4294967295 mkpasswd 0 Sep 23 16:29 src drwxr-xr-x+ 7 4294967295 mkpasswd 0 Oct 1 17:37 test drwxr-xr-x+ 2 4294967295 mkpasswd 0 Oct 1 16:02 test-output drwxr-xr-x+ 8 4294967295 mkpasswd 0 Oct 1 17:17 web
web is basically structured like the webapps/${project.name} directory in a Tomcat deployment. src/java and test/src/java trees are compiled into web/WEB-INF/classes.
I am still a novice with the Seam framework. It is a vast and powerful framework, but there still seems to be a lack of good material on integration testing best practices with Seam (e.g., configuring, running via Ant or Eclipse's TestNG plugin, troubleshooting problems).
I have only been able to setup the classpath and run my tests via Ant. Cannot get individual tests to run via the TestNG plugin. I cannot help but feel a little suspicious that something may be missing from the classpath, but I can successfully deploy and run the application... so why doesn't the test run and work?
Thanks in advance for your time and patience.
Chris.