I recommend creating an action context.  Here is the basic guide I followed to 
do so:

http://arsenalist.com/2007/06/18/unit-testing-struts-2-actions-spring-junit/ 

If you are not using spring or the struts2 spring plugin, you can cut out all 
the code around the applicationContext.


-----Original Message-----
From: paulbrickell [mailto:[EMAIL PROTECTED] 
Sent: Thursday, April 03, 2008 11:44 AM
To: user@struts.apache.org
Subject: Re: any struts 2 unit testers out there?


I am trying to deal with the same issue. Did you get any resolution?

Following on from the reply asking for a stack trace, here is what I am 
getting...


java.lang.NullPointerException
        at
com.opensymphony.xwork2.util.LocalizedTextUtil.findText(LocalizedTextUtil.java:299)
        at
com.opensymphony.xwork2.TextProviderSupport.getText(TextProviderSupport.java:172)
        at
com.opensymphony.xwork2.TextProviderSupport.getText(TextProviderSupport.java:87)
        at com.opensymphony.xwork2.ActionSupport.getText(ActionSupport.java:80)
        <SNIP>
        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.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
        at
org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
        at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
        at
org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
        at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
        at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
        at
org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
        at
org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
        at
org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
        at
org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
        at 
org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
        at
org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
        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)


It is caused by ActionContext.getContext() returning null. Quite obviously I do 
not have an action context during my unit testing.

Now I can certainly use the ActionContext.setContext() in my tests setup method 
to push one into thread local storage and that works OK. It isn't ideal though 
because ActionContext is a concrete class and so my choices then become a bit 
limited. 

I could create an instance but when I try this I find I have to create a rather 
large object model to make it actually work. To the point where I despair and 
give up.

Alternatively I could use a mock library (like easy mock). But I am not 
inclined to include a mocking library that requires byte code rewriting (not 
even for testing).

What I really want to do is inject a text provider into the ActionSupport 
class. At the top of the ActionSupport class is this...

private final transient TextProvider textProvider = new 
TextProviderFactory().createInstance(getClass(), this);

Damn its final and so I cannot inject my own text provider. 

BUT it uses a factory, thats good. I know I will have a look at the factory I 
bet I can monkey with that and inject a mock. Nope. It's all instance based. No 
way I can get in there. And thats that. Now what do I do?

I can see two (half) workable solutions.

One is to override the the getText method in the action class when I 
instantiate it during testing. So I end up doing this in all my action unit 
tests...

        Action action = new MyAction()
        {
            @Override
            public String getText(String textName)
            {
                return "mocked";
            }
        };

It works, but its cheese.

Or two I can add a level of indirection in my action class, like so...


    String text =
MyTextProviderFactory.getInstance(class.name).getText("some.property");

Then I can use a delegate to the real text provider during live code and a mock 
of my own text provider during testing. The question here is, Why for the love 
of Pete, why?

So in conclusion there are at least four options for testing Action classes 
that use get text.

1. Build an action context by hand. (Too hard) 2. Use a class rewriting mocking 
library. (Not on my watch) 3. Mock the get text method. (Cheese) 4. Add another 
level of indirection. (Man thats just annoying)

Comments?

BTW If you got this far, thanks for taking the time.
Paul B.




Session Mwamufiya wrote:
> 
> Hi All,
> 
> Would someone let me know whether it's possible to tweak something so 
> that JUnit test code can run on an action method that calls the 
> ActionSupport method getText() to fetch string resources from a 
> package.properties file.
> As it stands, I keep getting a null exception when getText() is called 
> during the unit test.
> 
> Thanks,
> Session
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
> 
> 
> 

--
View this message in context: 
http://www.nabble.com/any-struts-2-unit-testers-out-there--tp13437046p16467812.html
Sent from the Struts - User mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

----------------------------------------------------------------------
CONFIDENTIALITY NOTICE This message and any included attachments are from 
Cerner Corporation and are intended only for the addressee. The information 
contained in this message is confidential and may constitute inside or 
non-public information under international, federal, or state securities laws. 
Unauthorized forwarding, printing, copying, distribution, or use of such 
information is strictly prohibited and may be unlawful. If you are not the 
addressee, please promptly delete this message and notify the sender of the 
delivery error by e-mail or you may call Cerner's corporate offices in Kansas 
City, Missouri, U.S.A at (+1) (816)221-1024.

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to