I'm pretty new to RF but by reading through various posts regarding
the testing of RF i came up with the following solution that seems to
work well so far with spring

First an abstract test case that your unit test would extends

@TransactionConfiguration(defaultRollback = false)
@ContextConfiguration({ "classpath:spring/somecontext.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
public abstract class SpringRequestFactoryServletTest<T extends
RequestFactory>{

    @Autowired
    SpringRequestFactoryServlet springRequestFactoryServlet;

    protected MockServletConfig servletConfig = new
MockServletConfig();
    protected MockServletContext servletContext = new
MockServletContext();
    protected T requestFactory;
    private SpringRequestTransport transport;
    private final Class<? extends T> requestFactoryClass;

    public SpringRequestFactoryServletTest(Class<? extends T>
requestFactoryClass) {
        this.requestFactoryClass = requestFactoryClass;
    }

    @Before
    public void init() {
        requestFactory = create(requestFactoryClass);
        springRequestFactoryServlet.setServletConfig(servletConfig);
        springRequestFactoryServlet.setServletContext(servletContext);

        String[] contexts = new String[] { "classpath:spring/
somecontext.xml" };
        XmlWebApplicationContext webApplicationContext = new
XmlWebApplicationContext();
        webApplicationContext.setConfigLocations(contexts);
        webApplicationContext.setServletContext(servletContext);
        webApplicationContext.refresh();
        
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
webApplicationContext);
    }

    private T create(Class<? extends T> requestFactoryClass) {
        T t = RequestFactorySource.create(requestFactoryClass);
        transport = new SpringRequestTransport(springRequestFactoryServlet);
        t.initialize(new SimpleEventBus(), transport);
        return t;
    }


    /**
     * Allows firing a Request synchronously. In case of success, the
result is
     * returned. Otherwise, a {@link RuntimeException} containing the
server
     * error message is thrown.
     */
    public <T> T fire(Request<T> request) {
        return fire(request, null);
    }

    public <T> T fire(Request<T> request, String loginname) {
        ReceiverCaptor<T> receiver = new ReceiverCaptor<T>();
        MockHttpServletRequest httpRequest = new MockHttpServletRequest();
        MockHttpServletResponse httpResponse = new MockHttpServletResponse();
        transport.setRequest(httpRequest);
        transport.setResponse(httpResponse);
        if(loginname != null) {
            httpRequest.setUserPrincipal(new PrincipalMock(loginname));
        }
        request.fire(receiver);

        handleFailure(receiver.getServerFailure());
        return receiver.getResponse();
    }

    private void handleFailure(ServerFailure failure) {
        if (failure != null) {
            throw new RuntimeException(buildMessage(failure));
        }
    }

    private String buildMessage(ServerFailure failure) {
        StringBuilder result = new StringBuilder();
        result.append("Server Error. Type: ");
        result.append(failure.getExceptionType());
        result.append(" Message: ");
        result.append(failure.getMessage());
        result.append(" StackTrace: ");
        result.append(failure.getStackTraceString());
        return result.toString();
    }

}

The SpringRequestTransport looks like this

public class SpringRequestTransport implements RequestTransport {
    private final SpringRequestFactoryServlet requestFactoryServlet;
    private MockHttpServletRequest request;
    private MockHttpServletResponse response;

    public SpringRequestTransport(SpringRequestFactoryServlet
requestFactoryServlet) {
        this.requestFactoryServlet = requestFactoryServlet;
    }

    public void setRequest(MockHttpServletRequest request) {
        this.request = request;
    }

    public void setResponse(MockHttpServletResponse response) {
        this.response = response;
    }

    @Override
    public void send(String payload, TransportReceiver receiver) {
        try {
            request.setContentType("application/json");
            request.setCharacterEncoding("UTF-8");
            request.setContent(payload.getBytes());
            requestFactoryServlet.handleRequest(request, response);
            String contentAsString = response.getContentAsString();
            receiver.onTransportSuccess(contentAsString);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

The SpringRequestFactoryServlet

@Controller
@Transactional
public class SpringRequestFactoryServlet extends RequestFactoryServlet
implements ServletContextAware, ServletConfigAware{

    private static final ThreadLocal<ServletContext> perThreadContext
=
              new ThreadLocal<ServletContext>();
    private ServletContext servletContext;
    private ServletConfig servletConfig;

    public SpringRequestFactoryServlet() {
        super(new DefaultExceptionHandler(), new
SpringServiceLayerDecorator());
    }
    /**
     * Returns the thread-local {@link ServletContext}
     *
     * @return the {@link ServletContext} associated with this servlet
     */
    public static ServletContext getThreadLocalServletContext() {
      return perThreadContext.get();
    }

    @RequestMapping("/gwtRequest")
    public void handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
        perThreadContext.set(servletContext);
        super.doPost(request, response);
    }

    @Override
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    @Override
    public ServletConfig getServletConfig() {
        return servletConfig;
    }

    @Override
    public void setServletConfig(ServletConfig servletConfig) {
        this.servletConfig = servletConfig;
    }

    @Override
    public ServletContext getServletContext() {
        return servletContext;
    }

}

The SpringServiceLayerDecorator

public class SpringServiceLayerDecorator extends ServiceLayerDecorator
{

    @Override
    public <T extends Locator<?, ?>> T createLocator(Class<T> clazz) {
        ApplicationContext ctx =
WebApplicationContextUtils.getWebApplicationContext(
                SpringRequestFactoryServlet.getThreadLocalServletContext());
        Object bean = ctx.getBean(clazz);
        return (T) (bean != null ? bean : super.createLocator(clazz));
    }
}

Then a test case that extends SpringRequestFactoryServletTest would
look like the one i describe in

http://groups.google.com/group/google-web-toolkit/browse_thread/thread/e43cf969fc6463a6/b2ca8b7f450f9dbe

where i run into a problem with RF because of the deltas send. But at
least with the above structure i was able to do tests using the
requestfactory as i would use it from the client and see that it
validates on the RF and could debug it which was quite helpful.

Dominik

-- 
You received this message because you are subscribed to the Google Groups 
"Google Web Toolkit" group.
To post to this group, send email to google-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to 
google-web-toolkit+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-web-toolkit?hl=en.

Reply via email to