Arsenalist

The Toronto Raptors Blog with an Arsenal touch

Unit Testing Struts 2 Actions wired with Spring using JUnit

Posted by Arsenalist on June 18, 2007

This post has moved here.

86 Responses to “Unit Testing Struts 2 Actions wired with Spring using JUnit”

  1. Yin said

    Thanks for the code, it works nicely.

  2. Rick Evans said

    That is nice, very useful.

    Any chance of it being submitted as a patch to the S2 team so that it can be ‘polished’ (Javadoc’ced and suchlike) and included in the core, similar to the way that Spring provides integration test support classes in the spring-mock.jar library?

    Cheers
    Rick

  3. Francisco Rosa said

    Pretty nice. I do believe this is one of the places where Struts 2.0 could offer a lot more developer support. I have been tackling this issue for sometime and written also some utility classes to simplify Struts 2.0 + Spring unit testing…
    Here’s my take on it:

    http://fassisrosa.blogspot.com/2007/03/unit-testing-struts-20-part-2.html

  4. ki_ll said

    Thank you, it works great. You can also set the session into invocationContext:

    protected static HashMap session = new HashMap();
    // …

    protected Object createAction(Class clazz, String namespace, String name)
    throws Exception {
    // …
    proxy.getInvocation().getInvocationContext().setParameters(new HashMap());
    proxy.getInvocation().getInvocationContext().setSession(session);
    //…
    }

  5. Mike said

    This code has helped me a lot to get my action tests up and running. Thank you very much. A little problem remains, though, as we are using tiles too. When ever I try to execute an action that has as result type “tiles” I get an NPE in org.apache.struts2.view.tiles.TileResult.doExecute. It looks like the tiles listener (configured in web.xml) is not loaded. How does your code load web.xml actually (if at all)?

  6. arsenalist said

    Mike, the web.xml is not being loaded at all. I didn’t find the need for it in my test cases but that would be an excellent feature. If I have some time I’ll see where/how it can be loaded, if you figure it out, please post the solution…

  7. Thomas said

    This code is very helpful! It is exactly what I was looking for. However, I also have the same problem with tiles (as Mike above). If someone discovers the solution please post. I was going down the route of putting the tiles.xml in the ConfigurationManager, but I think this is the wrong path.

  8. Max said

    This is great thankyou!
    My web application uses a servlet filter to maintain my jpa entity manager open in my views (org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter). I’m new to unit testing and wondered how i could modify your base class so that my filter gets inluded before calling the struts dispatcher. I am guessing that this is a similar problem to the tiles problem that is described in a previous post, ie the need to load web.xml.

  9. John said

    I’m using Struts2 without Spring. And I would like to know how can I do a junit test using struts2??

    Thanks in advance

  10. Devarajan said

    Very good tutorial and it was very useful for me to test the complete flow in my application Thanks a lot.

  11. Scott said

    I cannot find an invoke() method on the proxy reference in your testValidation()example. Also, I had to modify the method signature of protected T createAction(Class clazz, String namespace, String name) as follows protected T createAction(Class clazz, String namespace, String name)

    Can you explain please?

    Thanks and great work!

  12. Scott said

    I see what happened to your source code now! the got sripped down on account of the HTML symbols! I have wrapped the method signature inside tags and it looks fine

    protected createAction(Class clazz, String namespace, String name)

    Now then, can you tell me why I am unable to find the invoke method on my proxy reference in the validation test code?

    Sweet examples brother,
    Scott

  13. Scott said

    Can you tell me how to get around the error caused by this jndi snafu? This is being thrown from the setUp() at appContext.refresh();

  14. arsenalist said

    Hi Scott, that should read proxy.execute(), not invoke(). I’ve fixed the example. Thanks for pointing out the error.

  15. Scott said

    Sweet! Is there a way to get the model from the action post execute method call?

  16. arsenalist said

    What do you mean? The return value of createAction() is the action class. Whatever public methods are available in your action are available during the tests. Just have a method which returns a model object in your action..

  17. Scott said

    Consider the following test:
    PayrollUpdateAction action = createAction(PayrollUpdateAction.class,
    “/pr”, “PayrollUpdate_notes”);
    action.setId(123L);
    String result = proxy.execute();
    PayrollUpdateTO model = action.getModel();
    System.out.println(model);
    assertEquals(“notes”,result );

    The model that prints is null! Spring injected the model and it was a live reference during the execute() behavior! I guess my question is one of accessing the action before it has wound it’s way through the interceptors during the return cycle

  18. Scott said

    My bad! I did not have Spring injecting the model. Sorry if you looked into this already.

    Peace,
    Scott

  19. Scott said

    createAction(PayrollUpdateAction.class,“/pr”, “PayrollUpdate_notes”);

    Are you only requiring the class name because Java Generics require it?

  20. arsenalist said

    Yup, only reason. Just to avoid a cast in the code that calls createAction(), it’s a little neater (I think).

  21. Scott said

    I agree this makes your factory method much cleaner! I really appreciate you offering up this solution. It is easy to see you are a very sharp cat.

  22. Scott said

    I have an Action that extends a parent who implements SessionAware. When I pass my subclass to the createAction and use the proxy to invoke it, I am getting a null pointer on the session Map. Should the setSession()be getting called if it is in the interceptor stack?

    Scott

  23. arsenalist said

    I haven’t worked with SessionAware so I’m not sure when it gets invoked, I just use the org.apache.struts2.ServletActionContext class to get hold of the request/response objects.

  24. Scott said

    All the interceptors are being called, however, since we are using a MockServletContext, naturally the request and session are Mocks too. I am trying to test an Action that implements these *aware* interfaces and of course the request and session maps are null. What would be the most natural way to push my own maps into these variables? Does it seem okay to simply call the setters on the action itself?

    Thanks,
    Scott

  25. Scott said

    One more comment on the interceptor invocation. I have the following test running:

    MemberMaintenance action = createAction(MemberMaintenance.class,”/member”, “MemberMaintenance_add”);
    (MemberMaintenance) proxy.getAction()).setSession(new HashMap());
    Map p = new HashMap();
    p.put(“id”, “1”);
    proxy.getInvocation().getInvocationContext().setParameters(p);
    String nextStep = proxy.execute();
    (ActionSupport) proxy.getAction()).getFieldErrors();

    and when the SessionAware interceptor is invoked, it is “resetting” my session Map to null! I have fixed it for the moment by changing the setSession(Map session) to check for a null Map being passed in. This really calls into question the advantage of having the interceptors included on the proxy.execute() test though. Comments?

    Scott

  26. Jason said

    Hello,

    I’m completely new to unit testing with struts and I’m having difficulty getting this example to work… Is this designed to run in the container or not? I thought not, but now I’m unsure. If it’s in container, can anyone point me to some examples of setting up container testing with junit?

    I’m also seeing an error saying either my applicationContext.xml cannot be found, or there’s a connection timeout parsing the xml. The file not found is fair enough, but can anyone suggest a reason for a connection timeout?

  27. arsenalist said

    Jason, this is not designed to run in a container. I don’t think running unit tests in a container is the way to go, you’re testing discrete action functionality, not how the container might behave.

    As for the appplicationContext.xml not being found, remember that they’re being loaded from the classpath using XmlWebApplicationContext so make sure your application context configuration is in your classpath and referenced correctly in config[]. If you prefer to load them from the file system instead, you can just override XmlWebApplicationContext.getResource().

  28. Jason said

    Thanks for your help. I seem to be locating the appContext ok now, but I have another question: No where in the code do you specify the location of the struts.xml. Is this also assumed to be on the classpath? Is there a way to load this from the filesystem if necessary?
    I’m getting an error now where none of my action mappings can be resolved, so I assume struts.xml to not being picked up.

  29. Elsa said

    Do you have the link to the source code?

  30. Elsa said

    It doesn’t seem to work with Struts 2.0.9. Thanks really.

  31. arsenalist said

    It’s working fine with 2.0.9 for me, might want to post the error you’re getting.

  32. samuel said

    Get this error:

    Unable to create SAX parser – Class: org.gjt.xpp.jaxp11.SAXParserFactoryImpl
    etc etc etc
    Caused by: javax.xml.parsers.ParserConfigurationException: validation is not supported
    at org.gjt.xpp.jaxp11.SAXParserFactoryImpl.newSAXParser(SAXParserFactoryImpl.java:100)
    at com.opensymphony.xwork2.util.DomHelper.parse(DomHelper.java:109)
    … 21 more

    The app code works on the server. Is some jar missing to my local test?

  33. Alan said

    The line:

    StrutsSpringObjectFactory.setObjectFactory(ssf);

    Does not works in struts 2.1 snapshot.

    I trace the code and find out that ObjectFactory in xworks 2.1 drop the singleton pattern. Would you mind giving me any suggestion to do the right same things in struts 2.1 (+ xworks 2.1)

  34. arsenalist said

    I’ve updated the source code to make it a little simpler, you don’t need StrutsSpringObjectFactory anymore. Try it again and let me know.

  35. Alan said

    Your sample is different from my case. Since I have other types of test that use spring, and I don’t want to startup more than one spring application context. In short, I wish to have a way that put a spring application context into struts context by hand when test setup, just as your previous sample that I can put the application context in a new StrutsSpringObjectFactory and assign the object factory to struts context. Is there any other way to do that? Thanks for your help.

  36. Mike said

    What changes would need to be made if I’m not using Spring? Thanks guys, tons of help!

  37. Amin said

    Hi there

    I have recently started developing Struts 2 and I am enjoying it, thanks to articles like these. I have used the base class and I am getting a NPE when it comes to tiles..and i see people have posted about this before and I was wondering if someone has done a solution and if so is there any sample code I could have a look at?

    Thanks

  38. Felix said

    Hi, thanks for this nice article. It helped me a lot.

    Maybe you can fix the typo(?) in PersonActionTest line 12 (pa->action).

    I am using Struts 2.0.11 with Tiles 2.0.4 (TilesDecorationFilter) and I am not facing the problems stated above. But I am extremely new to all the stuff ^^ so don’t trust me too much :)

  39. arsenalist said

    Thanks Felix, I’ve fixed the typo.

  40. Mike said

    I am also struggling to get this to work without Springs (just struts2). I know that isn’t the purpose of this article, but its so close :)

  41. Jon said

    Hi there

    I am trying this out for a project that uses freemarker and I am getting a ton of warning messages – I am testing it in intellij idea


    java.io.FileNotFoundException: class path resource [template/simple/common-attributes_en_US.ftl] cannot be resolved to URL because it does not exist

    2007-11-28 16:45:10,546 WARN [org.springframework.mock.web.MockServletContext:MockServletContext.java:264] : Couldn’t determine real path of resource class path resource [template/xhtml/form-close-validate.ftl]
    java.io.FileNotFoundException: class path resource [template/xhtml/form-close-validate.ftl] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/C:/Documents%20and%20Settings/jon/.m2/repository/org/apache/struts/struts2-core/2.0.11/struts2-core-2.0.11.jar!/template/xhtml/form-close-validate.ftl

    any tips?

  42. Rishi Kant Sharma said

    Hi

    I am learning struts2. this is realy good artical for me.
    if you have more artical related to struts2,Spring and hibernate published it.

    Rishi

  43. Mohammed said

    Hi,

    Really good example. Had a quick (and probably stupid) question though. How do you invoke a method in the action other than “execute”? I have an action class with all my CRUD methods in there and want to test each one with the full interceptor stack etc.

    Thanks,

    Mohammed

  44. arsenalist said

    Mohammed, you can define the configuration in your struts.xml:

    <action name="myAction" class="MyClass" method="myMethod"/>

    or you can just invoke myAction like this: myAction!myMethod.action and myMethod will be called.

  45. Mohammed said

    Thanks,

    Do you, or anyone else have this working with Maven 2?

    I’m having problems…

    (NB, my other unit tests work fine – just cant test action classes at the moment).

    I wasnt sure how to get the XML files (Spring, Struts etc) onto the test classpath, so ended up copying them to src/test/resources (there has to be a better way!)

    After doing that, i’m getting the following error

    Unable to load bean: type:org.apache.struts2.components.template.TemplateEngine class:org.apache.struts2.components.template.JspTemplateEngine – bean – jar:file:/C:/Documents%20and%20Settings/abdealim/.m2/repository/org/apache/struts2/struts2-core/2.0.9/struts2-core-2.0.9.jar!/struts-default.xml:34:150
    at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.register(XmlConfigurationProvider.java:208)

  46. Sri said

    Hey,

    I tried running the test customized to my application, but I am encountering an issue of Infinite Recursion Detected. I guess its something related to auto chaining not working, but am not sure. Appreciate your help in this regard

    I am getting the same error when running the junit test.
    Infinite recursion detected: [/login!input, /exceptionHandler, /exceptionHandler] – [unknown location]
    at com.opensymphony.xwork2.ActionChainResult.execute(ActionChainResult.java:207)
    at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:348)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:253)
    at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:50)
    at com.opensymphony.xwork2.ActionChainResult.execute(ActionChainResult.java:229)
    at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:348)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:253)
    at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:50)
    at gov.glin.web.struts.action.LoginActionTest.testValidLogin(LoginActionTest.java:21)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at junit.framework.TestCase.runTest(TestCase.java:154)
    at junit.framework.TestCase.runBare(TestCase.java:127)
    at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:69)
    at junit.framework.TestResult$1.protect(TestResult.java:106)
    at junit.framework.TestResult.runProtected(TestResult.java:124)
    at junit.framework.TestResult.run(TestResult.java:109)
    at junit.framework.TestCase.run(TestCase.java:118)
    at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
    here is the entry in the struts.xml

    { “input”, “login” }
    /login/login.ftl
    /home.action
    /changePassword.action?user=${user.userId}

  47. Arsenalist said

    Re: 45.

    src/test/resources and src/main/resources is the best way to put stuff in your classpath, not sure why you don’t like that. You can also define additional resources location in Maven if you need to.

  48. dalto said

    Hi,

    I’m very new to java, struts, spring, etc.. :P
    And i’m getting trouble to get this test working with my struts actions. I’m using eclipse and when I run the test I see from the Junit tab this error:

    org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from ServletContext resource [/WEB-INF/applicationContext.xml]; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/applicationContext.xml]
    Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/applicationContext.xml]
    at org.springframework.web.context.support.ServletContextResource.getInputStream(ServletContextResource.java:99)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:317)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:125)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:141)
    at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:123)
    at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:91)
    at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:94)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:292)
    at org.springframework.web.context.support.AbstractRefreshableWebApplicationContext.refresh(AbstractRefreshableWebApplicationContext.java:156)
    at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:246)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:184)
    at com.aix2.test.BaseStrutsTestCase.setUp(BaseStrutsTestCase.java:117)
    at junit.framework.TestCase.runBare(TestCase.java:125)
    at junit.framework.TestResult$1.protect(TestResult.java:106)
    at junit.framework.TestResult.runProtected(TestResult.java:124)
    at junit.framework.TestResult.run(TestResult.java:109)
    at junit.framework.TestCase.run(TestCase.java:118)
    at junit.framework.TestSuite.runTest(TestSuite.java:208)
    at junit.framework.TestSuite.run(TestSuite.java:203)
    at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:128)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

    I tryed to test if I was pointing to the right file and if it is readable putting this code snipet in my class constructor:


    File f = new File("WEB-INF/applicationContext.xml");
    if (f.exists() && f.isFile()) {
    try {
    System.out.println("file exists: " + f.getCanonicalPath());
    } catch (Exception e) {
    e.printStackTrace();
    }
    if (f.canRead()) {
    System.out.println("readable archive.");
    }
    }

    which prints:
    “file exists.
    readable archive”

    and then:

    web-15:23:54,968 DEBUG com.aix.estagio.AtividadesEstagioAction:41 - AtividadesEstagioActionTest() - start
    web-15:23:54,984 DEBUG com.aix2.test.BaseStrutsTestCase:88 - createAction(Class, String, String) - Erro ao criar ActionProxy: java.lang.NullPointerException
    web-15:23:54,984 ERROR com.aix2.test.BaseStrutsTestCase:90 - createAction(Class, String, String)
    java.lang.NullPointerException
    at com.aix2.test.BaseStrutsTestCase.createAction(BaseStrutsTestCase.java:76)
    at com.aix.test.webgiz.AtividadesEstagioActionTest.(AtividadesEstagioActionTest.java:45)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
    at junit.framework.TestSuite.createTest(TestSuite.java:131)
    at junit.framework.TestSuite.addTestMethod(TestSuite.java:114)
    at junit.framework.TestSuite.(TestSuite.java:75)
    at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestLoader.getTest(JUnit3TestLoader.java:102)
    at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestLoader.loadTests(JUnit3TestLoader.java:59)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:445)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

    after debugging I’ve found that the dispatcher object is null when in the createAction method.

    When is this object instantiated?
    Do you have any ideas on how to get this working for my case?

    Many thanks and sorry for the bad english.

  49. Arsenalist said

    dalto, you’re having a classpath issue. Just make sure your tests can find the application context at /WEB-INF/applicationContext.xml. Or you can tell Spring where to look for the files as shown in the example.

  50. Sri said

    Hi arsenalist,

    appreciate your inputs on issue 46 pls.

  51. Arsenalist said

    Sri, that to me looks like something wrong with your action configuration which is causing a recursion between the login!input action and your exceptionHandler. Is your exception handler by any chance redirecting to login!input and in turn login!input is throwing n exception thus causing the recursion?

    I believe the action is being invoked correctly which indicates that the test is setup fine, it’s just what happens after that is the problem.

  52. Sri said

    here is my struts entry

    { “input”, “login” }
    /login/login.ftl
    /home.action
    /changePassword.action?user=${user.userId}

    and my applicationContext entry

    I dont know from where the input method is invoked, and why my action fails which in turn calls exceptionHandler. frustrated with this.

  53. Sri said

    applicationContext

    struts entry

    { “input”, “login” }
    /login/login.ftl
    /home.action
    /changePassword.action?user=${user.userId}

  54. Sri said

    am not sure why my application entry and struts entry is cropped :(

  55. Arsenalist said

    This blog has some trouble dealing with XML, you’ll have to escape it when posting code. I think the “input” method is automatically invoked by Struts at some point (I could be wrong), you should try renaming the input method to something more precise and see what the behavior is.

  56. dalto said

    thanks for the reply!
    i’m new to java and i can’t understand what the classpath have to do with this issue.. do i have to add my project directory to the classpath?
    i already tried to fix this by specifying to where the file is like the exemple and it keep throwing the same error.. by the way, i only have the applicationContext.xml file and not the security one, can this cause any problem?

  57. dalto said

    i’ve added the MockServletContext package directory to the classpath, keeps throwing the same error in the setUp() method.

  58. dalto said

    i solved it by referencing the file this way:
    file///c:/workpath/project/WEB-INF/applicationContext.xml

    nice article, btw ;)

  59. Sri said

    hi arsenalist,

    Issue 46 I could resolve that issue now, the problem was there was an NPE which was thrown in ContextInterceptor because I didnt set the Session in the BaseTestCase

    proxy.getInvocation().getInvocationContext().setSession(sessionMap);

    and hence the infinite recursion. Good Lord I spent lot of time debugging for this. My bad.

    Thanks for your help arsenal.

  60. David Clarke said

    Thanks for posting this, in an ocean of mediocrity it is nice to stumble across the odd pearl.

    I’m prototyping my first struts2 app right now and having successfully configured actions/results using annotations I would like to be able to test them. Unfortunately as it stands and using your base test class I am unable to do that. Everything works as expected if I add the actions/results into struts.xml. I have already spent some time wading through the Dispatcher source and find myself very little the wiser. I thought perhaps by loading actionPackages in the initParams parameter of the Dispatcher constructor it might all magically start working. Unfortunately I’m still relatively new to java (from c#) and I really want to understand what I’m doing rather than rely on magic. I would really appreciate a few pointers.

  61. arsenalist said

    David, what’s the problem?

  62. David Clarke said

    Well, I would like to know how to enable your BaseStrutsTestCase class to work with action/result annotations.

  63. Mark said

    I also develop an application using Tiles. It would be really neccessary to mock out the TilesResult because these would be tested independently.

    I would also like to test Preparer classes, but my preparers could do nothing but return action results so that they can be tested.

  64. Mohammed said

    Hi,

    I’m getting this error, and have no idea where to even start looking for the problem. I’m using Maven 2, JUnit 4, Struts 2 + Spring.

    Unable to load bean: type:org.apache.struts2.components.template.TemplateEngine class:org.apache.struts2.components.template.JspTemplateEngine – bean – jar:file:/C:/Documents%20and%20Settings/abdealim/.m2/repository/org/apache/struts2/struts2-core/2.0.9/struts2-core-2.0.9.jar!/struts-default.xml:34:150
    at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.register(XmlConfigurationProvider.java:208)
    at org.apache.struts2.config.StrutsXmlConfigurationProvider.register(StrutsXmlConfigurationProvider.java:101)
    at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reload(DefaultConfiguration.java:131)
    at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:52)
    at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:395)
    at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:452)
    at com.sentaca.telusreporting.web.BaseStrutsTestCase.setUp(BaseStrutsTestCase.java:95)
    at com.sentaca.telusreporting.web.UserManagementActionTestCase.setUp(UserManagementActionTestCase.java:12)
    at junit.framework.TestCase.runBare(TestCase.java:132)
    at junit.framework.TestResult$1.protect(TestResult.java:110)
    at junit.framework.TestResult.runProtected(TestResult.java:128)
    at junit.framework.TestResult.run(TestResult.java:113)
    at junit.framework.TestCase.run(TestCase.java:124)
    at junit.framework.TestSuite.runTest(TestSuite.java:232)
    at junit.framework.TestSuite.run(TestSuite.java:227)
    at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:81)
    at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
    at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:138)
    at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:125)
    at org.apache.maven.surefire.Surefire.run(Surefire.java:132)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:290)
    at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:818)
    Caused by: java.lang.NoClassDefFoundError: javax/servlet/jsp/JspWriter
    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2357)
    at java.lang.Class.getDeclaredConstructors(Class.java:1808)
    at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.register(XmlConfigurationProvider.java:198)
    … 25 more

  65. David Clarke said

    Hey there – I guess your attention is currently elsewhere. I am wondering if you have had any opportunity to think about how your BaseStrutsTestCase could be made annotation-aware. I realise this may not be high on your list of priorities but I would certainly appreciate some pointers as to how I might go about this. I’m currently in the middle of a prototype exercise and I will need to revisit this soonish. Being able to test my actions is higher on my list of priorities than using annotations so I may need to revert to the xml-style configuration if I can’t get this working.

  66. It is actually quite easy to make this base class annotation aware. Just add this before line 86 (in setUp()) in BaseStrutsTestCase:


    HashMap params = new HashMap();
    params.put("actionPackages", "your.action.package1,your.action.package1");

    and then modify line 86 to read:


    dispatcher = new Dispatcher(servletContext, params);

    You basically need to tell the dispatcher to scan your classpath. actionPackages is the parameter which makes this happen in web.xml. If you want to understand why and how this works check out the Dispatcher code at Krugle:

    http://www.krugle.org/kse/files/svn/svn.apache.org/struts/current/struts2/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java

  67. arsenalist said

    Thank you Hardy for that! I’ve updated the post.

  68. David Clarke said

    Thanks Hardy, that would be worth a woot! Your timing is impeccable.

  69. Ismath said

    I’m getting this error when I run my JUnit Test class

    java.lang.SecurityException: class “junit.framework.JUnit4TestCaseFacade”‘s signer information does not match signer information of other classes in the same package
    at java.lang.ClassLoader.checkCerts(Unknown Source)
    at java.lang.ClassLoader.preDefineClass(Unknown Source)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.security.SecureClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.access$100(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClassInternal(Unknown Source)
    at org.junit.internal.runners.OldTestClassRunner$OldTestClassAdaptingListener.asDescription(OldTestClassRunner.java:41)
    at org.junit.internal.runners.OldTestClassRunner$OldTestClassAdaptingListener.startTest(OldTestClassRunner.java:31)
    at junit.framework.TestResult.startTest(TestResult.java:151)
    at junit.framework.TestResult.run(TestResult.java:103)
    at junit.framework.TestCase.run(TestCase.java:120)
    at junit.framework.TestSuite.runTest(TestSuite.java:230)
    at junit.framework.TestSuite.run(TestSuite.java:225)
    at org.junit.internal.runners.OldTestClassRunner.run(OldTestClassRunner.java:76)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

    Any idea on what this means ? Thanks !

    Ismath

  70. felix said

    Hi, just one idea to improve the code. In class PersonActionTest you use

    assertEquals(result, “success”);

    which will result in some misleading error messages by JUnit on failure, like

    [junit] junit.framework.ComparisonFailure: expected: but was:

    The JUnit API documentation states:

    assertEquals(java.lang.String expected, java.lang.String actual)

    So just flipping the variables will make things clearer.

    Greets, Felix

  71. Andrew said

    This really works well, but I have an obstacle. We have custom validators and have placed the validators.xml file in the /WEB-INF/classes/ directory as prescribed. The site works fine, however, the test case for the action does not. Running against the action produces the exception: java.lang.IllegalArgumentException: There is no validator class mapped to the name myCustomValidator.

    I’m not sure how to incorporate this into the above test configuration. Do you have a suggestion? Thanks!

  72. Andrew said

    Actually, I just figured it out, but perhaps you know a better way. I added:

    ValidatorFactory.registerValidator(“myCustomValidator”, “x.y.z.web.validators.MyCustomValidator”);

    as the first line in my unit test and it works. By the way, I’m also using your base test to get an action so that I can set up the validator context in other tests that test validators independently. It really made it easy. Thanks again.

  73. mani said

    good

  74. Timothy said

    Hi, thanks for this post. My colleagues and I are finding it very helpful.

    Just one nit-picking I couldn’t resist though.
    It seems you are using assert…() method’s parameters in reverse order. According to the API doc, ‘expected’ value should come first, then ‘actual’. I don’t think this would degrade the quality of tests in terms of accuracy, but for the people reading the tests (and adopting these in their own projects), it may be confusing at times since it goes against the usual convention.

    Anyways, cheers for the Arsenal!

  75. Jignesh said

    Hi,I am having struts2 + hibernate application no spring configuration.

    I used the same abstract BaseStrutsTestCase class with only change to commented out this code from setUp() method
    /*
    if( applicationContext == null ) {
    // this is the first time so initialize Spring context
    servletContext = new MockServletContext();
    servletContext.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
    CONFIG_LOCATIONS);
    applicationContext = (new ContextLoader()).initWebApplica
    */

    Test cases works fine with struts2 application only.

    But the only problem is that i am not able to pass the request parameters to the action class while able to pass the
    params by SettingDomainObjects.

    It means testInterceptorsBySettingDomainObjects() this is working fine while this is not testInterceptorsBySettingRequestParameters() from the above example.

    Can anybody tell me what is the problem here ?

  76. jaalex said

    If we want to use a different struts xml than the default one (say, struts-test.xml) , it can be specified as :

    params.put(“config”,”struts-default.xml,struts-plugin.xml,struts-test.xml”);

  77. Krishna said

    somebody copied your article word by word here http://itefforts.blogspot.com/2007/08/struts2-spring-junit.html

  78. Bigster said

    Hi all,

    I´ve read the posts, and someone has the need to put in the CONFIG_LOCATIONS the web-xml?

    I´ve there de JNDI datasources needed by Spring.

    How, based in the example, could i load to the classpath the web.xml??

    cheers

  79. arsenalist said

    Bigster, to load config locations, you can just specify it using the way it’s shown in Line 75 of the setUp() method.

    servletContext.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM, CONFIG_LOCATIONS);

  80. Bigster said

    arsenalist,

    That´s what i´ve tried :

    private static final String CONFIG_LOCATIONS =
    “WEB-INF/web.xml,”+ “hibernate.cfg.xml,” + “aplicationContext-dao.xml,” + “applicationContext-resources.xml,” + “applicationContext-service.xml,” + “applicationContext-struts.xml”;

    it throws a FileNotfoundExecption, it don´t find tha web.xml in the WEB-INF folder.

    any help?

  81. Tavo said

    Hi. I’m trying to implement this solution, but i have problem with the import
    “import org.springframework.mock.web.MockHttpServletRequest;”, don’t recognises and don’t exist in spring 2.0.4 jar file. Any idea?. Congratulations Arsenal and thank you for your article.

  82. Tavo said

    Resolved. The spring jar file does’n contain the mock jar, is only the core. Must be include the mock jar file in the classpath. Now i’m trying the test my classes. Thks.

  83. vd greg said

    Hi I am very new to struts2. I am using tiles and like to use your code to develop some test cases for my application. The problem is I was using any namespace tag before in the package area.
    So when I use namespace tag and put some value in it, the body jsp displayed but not the left menu, top menu and etc.

    Why other jsp are not getting displayed?
    —Struts.xml———————————————–

    myTest
    Error

    ————————————————————
    Tiles.xml

  84. vd greg said

    Hi I am very new to struts2. I am using tiles and like to use your code to develop some test cases for my application. The problem is I was using any namespace tag before in the package area.
    So when I use namespace tag and put some value in it, the body jsp displayed but not the left menu, top menu and etc.

    Why other jsp are not getting displayed?
    —Struts.xml———————————————–

    myTest
    Error

    ————————————————————
    Tiles.xml

  85. vd greg said


    ---Struts.xml-----------------------------------------------

    myTest
    Error

    ------------------------------------------------------------
    Tiles.xml

  86. vd greg said

    —Struts.xml———————————————–

    package name=”vd” namespace=”/vd” extends=”something”
    action name=”vdTest” class=”vdAction”
    result type=”tiles” myTest result
    result name=”error” type=”tiles” Error result
    action>
    package
    ————————————————————
    Tiles.xml
    definition name=”default” template=”/WEB-INF/jsp/default.jsp”
    put-attribute name=”title” value=”Management System”
    put-attribute name=”header” value=”/html/header.html”
    put-attribute name=”menu” value=”/WEB-INF/jsp/menu.jsp”
    put-attribute name=”footer” value=”/html/footer.html”
    put-attribute name=”body” value=”/html/main.html”
    definition>
    definition name=”myTest” extends=”default”
    put-attribute name=”body” value=”/WEB-INF/jsp/vdTest.jsp”
    definition

Sorry, the comment form is closed at this time.