1 2 Previous Next 26 Replies Latest reply on Jul 23, 2012 4:12 AM by lfryc

    Designing Warp extension for testing Spring MVC

    jmnarloch

      Hi,

       

      I had played with the alpha 1 of Warp and I have to say that it's pretty cool.

       

      I came up with an idea to create an extension particular for testing SpringMVC, I hacked the code a bit and came up with fallowing result: https://github.com/jmnarloch/arquillian-extension-warp/tree/Spring/extension

       

      The code is pretty simple, but it gives the proof of concept for this idea.

       

      Edit: a test example that demonstrates the usage:

      {code}

      @WarpTest

      @RunWith(Arquillian.class)

      public class WelcomeControllerTestCase {

       

       

          @Drone

          WebDriver browser;

       

       

          @ArquillianResource

          URL contextPath;

       

       

          @Deployment

          public static WebArchive createDeployment() {

       

       

              File[] libs = DependencyResolvers.use(MavenDependencyResolver.class)

                      .loadEffectivePom("pom.xml")

                      .artifacts("org.springframework:spring-webmvc:3.1.1.RELEASE")

                      .resolveAsFiles();

       

       

              return ShrinkWrap.create(WebArchive.class, "spring-test.war").addClasses(WelcomeController.class)

                      .addAsWebInfResource("WEB-INF/web.xml", "web.xml")

                      .addAsWebInfResource("WEB-INF/welcome-servlet.xml", "welcome-servlet.xml")

                      .addAsWebInfResource("WEB-INF/jsp/welcome.jsp", "jsp/welcome.jsp")

                      .addAsLibraries(libs);

          }

       

       

          @Test

          @RunAsClient

          public void test() {

              Warp.execute(new ClientAction() {

       

       

                  @Override

                  public void action() {

                      browser.navigate().to(contextPath + "welcome.do");

                  }

              }).verify(new WelcomeControllerVerification());

          }

       

       

          public static class WelcomeControllerVerification extends ServerAssertion {

       

       

              private static final long serialVersionUID = 1L;

       

       

              @Inject

              private ModelAndView modelAndView;

       

       

              @AfterServlet

              public void testWelcome() {

       

       

                  assertEquals("welcome", modelAndView.getViewName());

                  assertEquals("Warp welcomes!", modelAndView.getModel().get("message"));

              }

          }

      }

      {code}

       

       

      The most inportant part is the org.jboss.arquillian.warp.extension.spring.TestDispatcherServlet (I was thinkng about renaming it rather into WarpDispatcherServlet) which captures the execution of the request and stores it in SpringMvcResult. The SpringMvcResult could be injected into the ServerAssertion in order to retrieve the execution state.

       

      I'm planning to extend the code a bit.

       

      • First I would like add additional properties to the SpringMvcResult. Ideas:
        • Handler that was used for this request.
        • HttpServletRequest
      • Second thing, I would like create a shorcut for injecting the properties. In meaning injecting directly the properties stored in SpringMVCResult.

      {code}

        public static class WelcomeControllerVerification extends ServerAssertion {

       

              @Inject

              private SpringMvcResult mvcResult;

       

              // instead of mvcResult.getModelAndView()

              @Inject

              private ModelAndView modelAndView;

       

              // instead of mvcResult.getException()

              @Inject

              private Exception exception;

       

              @AfterServlet

              public void test() {

       

              }

          }

      }

      {code}

       

      • I've used the javax.inject.Inject for marking the fields that need to be injected, but maybe it would be better to use some custom annotation like @ArquillinResource or something complety new like @SpringMvcResource (or @SpringMvcContext maybe) or similar.

       

      Last thing. Is there a way to inject a ServletRequest into the extension code? I had used the BeforeServletEvent, which I think would be nice to have in SPI rather then in implementation, as workaround to retrieve the request object.

        • 1. Re: Designing Warp extension for testing SpringMVC
          jmnarloch

          Btw. Maybe some one has a better idea for the name then simple "warp-spring"?

          • 2. Re: Designing Warp extension for testing SpringMVC
            lfryc

            Hi Jakub,

             

            fantastic job with the integration!

            I'm planning to extend the code a bit.

             

            • First I would like add additional properties to the SpringMvcResult. Ideas:
              • Handler that was used for this request.
              • HttpServletRequest
            • Second thing, I would like create a shorcut for injecting the properties. In meaning injecting directly the properties stored in SpringMVCResult.

             

            Great ideas, there are my $0.2:

             

            • HttpServletRequest should be injectable by Warp Core
            • +1 to Handler (I'm not familiar with Spring MVC, but I imagine it could be pretty useful for veryfing internal state)
            • +1 to shortcuts, that's something I definitely plan to Phaser (JSF)

             

             

            • I've used the javax.inject.Inject for marking the fields that need to be injected, but maybe it would be better to use some custom annotation like @ArquillinResource or something complety new like @SpringMvcResource (or @SpringMvcContext maybe) or similar.

            I think Resource Provider is the way - providing injections through @ArquillianResource.

             

            Last thing. Is there a way to inject a ServletRequest into the extension code? I had used the BeforeServletEvent, which I think would be nice to have in SPI rather then in implementation, as workaround to retrieve the request object.

            Hmm, good question.

             

            Warp should allow to inject any Arquillian resource extension! -> ARQ-979

            And ServletRequest should be one of injectable resources. ;-) -> ARQ-980

            But additionally, we could do BeforeServletEvent and AfterServletEvent part of API.

            It might be handy to extensions. -> ARQ-981

             

            Btw SPI wasn't polished in scope of Alpha1, so if you would have any improvement ideas / extension points, don't hesitate to reach me on #jbosstesting or here!

            1 of 1 people found this helpful
            • 3. Re: Designing Warp extension for testing SpringMVC
              lfryc

              Btw. Maybe some one has a better idea for the name then simple "warp-spring"?

              I'm not convinced naming extensions by the new artificial names (I know, I did so with JSF ~ Phaser, but it might not be good decision).

               

              Naming the Warp extensions might bring obscurity, and users might simply get lost in naming.

              It might be enough to focus on just one name: Arquillian Warp and call its extension specifically:

               

              • Arquillian Warp Spring
              • Arquillian Warp JSF
              • Arquillian Warp Wicket
              • Arquillian Warp Atmosphere
              • ...
              • 4. Re: Designing Warp extension for testing SpringMVC
                lfryc

                Btw Right now, the only useful callbacks are @AfterServlet, @BeforeServlet with Spring extension.

                 

                Does not  Spring / Spring MVC havesome lifecycle phases, where we could introduce new lifecycle callbacks similarly to JSF phases?

                • 5. Re: Designing Warp extension for testing SpringMVC
                  jmnarloch

                  Thanks Lukáš

                  Lukáš Fryč wrote:

                   

                  Warp should allow to inject any Arquillian resource extension! -> ARQ-979

                  And ServletRequest should be one of injectable resources. ;-) -> ARQ-980

                  But additionally, we could do BeforeServletEvent and AfterServletEvent part of API.

                  It might be handy to extensions. -> ARQ-981

                   

                  Btw SPI wasn't polished in scope of Alpha1, so if you would have any improvement ideas / extension points, don't hesitate to reach me on #jbosstesting or here!

                   

                  I'm going to work on the extension, although Your help will be here invaluable

                   

                  In short therme I'm planning to do fallowing changes:

                  • Rename the TestDispatcherServlet into WarpDispatcherServlet
                  • Add the handler and interceptors to SpringMvcResult.
                  • Make use of the @ArquillianResource
                  • Turn SpringMvcResult into interface rather then cocnreate class.

                   

                  While Warp will gain new functionalities through time (like ARQ-979) I will try to utilize them in my code.

                  If I would be able to help you somehow then let me know.

                   

                  Off topic: I was thinking, what resource we could inject into ServerAssertion besides the HttpServletRequest, the bunch of ideas would be:

                  • How about the list of Cookies added into the resposnse? I guess they could be easily caputred through mocked HttpServletRequest in the WarpFilter.
                  • Current Session, if it exists.

                   

                  What do you think?

                  • 6. Re: Designing Warp extension for testing SpringMVC
                    jmnarloch

                    Lukáš Fryč wrote:

                     

                    Btw Right now, the only useful callbacks are @AfterServlet, @BeforeServlet with Spring extension.

                     

                    Does not  Spring / Spring MVC havesome lifecycle phases, where we could introduce new lifecycle callbacks similarly to JSF phases?

                     

                    Unfortunelty the Spring MVC does not have any type of lifecycle callbacks. Although, we could add some artificial ones triggered through the TestDispatcherServlet, but I don't thnik that there will be much scenarios when the will be used.

                    • 7. Re: Designing Warp extension for testing SpringMVC
                      lfryc

                      While Warp will gain new functionalities through time (like ARQ-979) I will try to utilize them in my code.

                      If I would be able to help you somehow then let me know.

                      Just tell what issue appeals you and you can make it real. ;-)

                       

                       

                      Off topic: I was thinking, what resource we could inject into ServerAssertion besides the HttpServletRequest, the bunch of ideas would be:

                      • How about the list of Cookies added into the resposnse? I guess they could be easily caputred through mocked HttpServletRequest in the WarpFilter.
                      • Current Session, if it exists.

                      I think resources comes in two variants:

                       

                      1) objects that can't be accessed any other way (HttpServletRequest)

                      2) objects that are accessible from base (cookies, session)

                       

                      If we will too much focus on (2), it will add much complexity.

                      I would add such sugar once it will be pretty clear it is needed.

                       

                       

                      In short therme I'm planning to do fallowing changes:

                      • Rename the TestDispatcherServlet into WarpDispatcherServlet
                      • Add the handler and interceptors to SpringMvcResult.
                      • Make use of the @ArquillianResource
                      • Turn SpringMvcResult into interface rather then cocnreate class.

                      +1 seems great - once ready, let me know (open pull request) and we can integrate Spring into master.

                      • 8. Re: Designing Warp extension for testing SpringMVC
                        lfryc

                        I was actually thinking that we could turn the ServerAssertions to CDI beans (register them to BeanManager) - then they would be able to receive events, produce alternative beans, etc.

                         

                        Would that be useful for Spring integration?

                        • 9. Re: Designing Warp extension for testing SpringMVC
                          jmnarloch

                           

                          In short therme I'm planning to do fallowing changes:

                          • Rename the TestDispatcherServlet into WarpDispatcherServlet
                          • Add the handler and interceptors to SpringMvcResult.
                          • Make use of the @ArquillianResource
                          • Turn SpringMvcResult into interface rather then cocnreate class.

                          +1 seems great - once ready, let me know (open pull request) and we can integrate Spring into master.

                           

                          I can make that even today, so would you like it to have in the repo or should I rather work in my own fork?

                          • 10. Re: Designing Warp extension for testing SpringMVC
                            jmnarloch

                            Lukáš Fryč wrote:

                             

                            I was actually thinking that we could turn the ServerAssertions to CDI beans (register them to BeanManager) - then they would be able to receive events, produce alternative beans, etc.

                             

                            Would that be useful for Spring integration?

                            Not sure, but probably that's the good idea to make the extensions work along with the Warp. I would say that it definietly would not brake anything

                            • 11. Re: Designing Warp extension for testing SpringMVC
                              jmnarloch

                              I come across a problem, whenever I annotated a field with @ArquillianResource in ServerAssertion I'm getting an error:

                               

                               

                              {code}

                              21:56:54,854 ERROR [org.apache.catalina.connector.CoyoteAdapter] (http--127.0.0.

                              1-8080-1) An exception or error occurred in the container during the request pro

                              cessing: java.lang.ArrayIndexOutOfBoundsException: 8192

                                      at org.apache.coyote.http11.InternalOutputBuffer.write(InternalOutputBuf

                              fer.java:698) [jbossweb-7.0.13.Final.jar:]

                                      at org.apache.coyote.http11.InternalOutputBuffer.write(InternalOutputBuf

                              fer.java:607) [jbossweb-7.0.13.Final.jar:]

                                      at org.apache.coyote.http11.InternalOutputBuffer.sendHeader(InternalOutp

                              utBuffer.java:479) [jbossweb-7.0.13.Final.jar:]

                                      at org.apache.coyote.http11.Http11Processor.prepareResponse(Http11Proces

                              sor.java:1648) [jbossweb-7.0.13.Final.jar:]

                                      at org.apache.coyote.http11.Http11Processor.action(Http11Processor.java:

                              998) [jbossweb-7.0.13.Final.jar:]

                                      at org.apache.coyote.Response.action(Response.java:190) [jbossweb-7.0.13

                              .Final.jar:]

                                      at org.apache.coyote.Response.sendHeaders(Response.java:390) [jbossweb-7

                              .0.13.Final.jar:]

                                      at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:

                              335) [jbossweb-7.0.13.Final.jar:]

                                      at org.apache.catalina.connector.OutputBuffer.close(OutputBuffer.java:30

                              1) [jbossweb-7.0.13.Final.jar:]

                                      at org.apache.catalina.connector.Response.finishResponse(Response.java:4

                              79) [jbossweb-7.0.13.Final.jar:]

                                      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.jav

                              a:395) [jbossweb-7.0.13.Final.jar:]

                                      at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java

                              :877) [jbossweb-7.0.13.Final.jar:]

                               

                              {code}

                               

                              The direct cause of the error seems to be buffer overflow, but I'm gessing that the real cause is the serialization of the @ArquillianResource type. It has recursive declaration to itself, may this be a problem?

                              • 12. Re: Designing Warp extension for testing SpringMVC
                                lfryc

                                I guess the size of the response header is exceeded [1].

                                 

                                Could you please file Warp issue?

                                 

                                [1] http://www.findsol.com/blog/java-lang-arrayindexoutofboundsexception/

                                • 13. Re: Designing Warp extension for testing SpringMVC
                                  jmnarloch

                                  In short therme I'm planning to do fallowing changes:

                                  • Rename the TestDispatcherServlet into WarpDispatcherServlet
                                  • Add the handler and interceptors to SpringMvcResult.
                                  • Make use of the @ArquillianResource
                                  • Turn SpringMvcResult into interface rather then cocnreate class.

                                   

                                   

                                  I've done the changes, although for now I omitted the @ArquillianResource support. Instead I introduced custom @SpringMvcResource that is being used by test enricher.

                                   

                                  Currently an example ServerAssertion could look like this:

                                   

                                  {code}

                                  public static class WelcomeControllerVerification extends ServerAssertion {

                                   

                                          private static final long serialVersionUID = 1L;

                                   

                                          // an aggregated state of the DispatcherServlet execution, allows to access the state through properties, e.g. mvcResult.getModelAndView()

                                          @SpringMvcResource

                                          private SpringMvcResult mvcResult;

                                   

                                          // the model and view returned from the controller

                                          @SpringMvcResource

                                          private ModelAndView modelAndView;

                                   

                                          // the handler that was used for processing the request

                                          @SpringMvcResource

                                          private HandlerMethod handler;

                                   

                                          // array of interceptors

                                          @SpringMvcResource

                                          private HandlerInterceptor[] interceptors;

                                   

                                          // exception thrown from controller, if any

                                          @SpringMvcResource

                                          private Exception exception;

                                   

                                          @AfterServlet

                                          public void testWelcome() {

                                   

                                              assertEquals("welcome", modelAndView.getViewName());

                                              assertEquals("Warp welcomes!", modelAndView.getModel().get("message"));

                                          }

                                      }

                                   

                                  {code}

                                  • 14. Re: Designing Warp extension for testing SpringMVC
                                    jmnarloch

                                    Hi,

                                     

                                    I was wondering what will happen if I will need to do multiple request in the ClientAction, let's consider a scenario when I'm retrieving the page through GET request and then I'm submiting a form using the selenium WebDriver. What will happen then?

                                    1 2 Previous Next