1 2 Previous Next 26 Replies Latest reply: Jul 23, 2012 4:12 AM by Lukáš Fryč RSS

Designing Warp extension for testing Spring MVC

Jakub Narloch Novice

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:

@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"));
        }
    }
}

 

 

 

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.
  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() {

        }
    }
}

 

 

  • 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
    Jakub Narloch Novice

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

  • 2. Re: Designing Warp extension for testing SpringMVC
    Lukáš Fryč Master

    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!

  • 3. Re: Designing Warp extension for testing SpringMVC
    Lukáš Fryč Master

    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
    Lukáš Fryč Master

    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
    Jakub Narloch Novice

    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
    Jakub Narloch Novice

    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
    Lukáš Fryč Master

    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
    Lukáš Fryč Master

    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
    Jakub Narloch Novice

     

    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
    Jakub Narloch Novice

    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
    Jakub Narloch Novice

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

     

     

    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:]
    
    

     

     

    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
    Lukáš Fryč Master

    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
    Jakub Narloch Novice

    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:

     

    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"));
            }
        }
    
    

     

  • 14. Re: Designing Warp extension for testing SpringMVC
    Jakub Narloch Novice

    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