views:

21

answers:

2

I'm trying to write a test that isolates the failure to load a property because no Session exists.

The following path fails

ERROR [http-8081-14] LazyInitializationException.setSessionAttribute(223) | could not initialize proxy - no Session
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:86)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:140)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
    at jaci.model.web.Shipment_$$_javassist_4.toString(Shipment_$$_javassist_4.java)
    at java.lang.String.valueOf(String.java:2827)
    at java.lang.StringBuilder.append(StringBuilder.java:115)
    at jaci.model.web.Web.toString(Web.java:259)
    at java.lang.String.valueOf(String.java:2827)
    at java.lang.StringBuffer.append(StringBuffer.java:219)
    at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:173)
    at org.slf4j.helpers.MessageFormatter.format(MessageFormatter.java:111)
    at org.slf4j.impl.Log4jLoggerAdapter.debug(Log4jLoggerAdapter.java:206)
    at jaci.web.ProcessingJobController.setSessionAttribute(ProcessingJobController.java:223)
    at jaci.web.ProcessingJobController.setSessionWeb(ProcessingJobController.java:219)
    at jaci.web.ProcessingJobController.initSessionJobAndWeb(ProcessingJobController.java:183)
    at jaci.web.ProcessingJobController.handlePost(ProcessingJobController.java:91)
    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:597)
    at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.doInvokeMethod(HandlerMethodInvoker.java:421)
    at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:136)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:326)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:313)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at com.opensymphony.sitemesh.webapp.SiteMeshFilter.obtainContent(SiteMeshFilter.java:129)
    at com.opensymphony.sitemesh.webapp.SiteMeshFilter.doFilter(SiteMeshFilter.java:77)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:378)
    at org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
    at org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.ui.SessionFixationProtectionFilter.doFilterHttp(SessionFixationProtectionFilter.java:67)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.ui.ExceptionTranslationFilter.doFilterHttp(ExceptionTranslationFilter.java:101)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.providers.anonymous.AnonymousProcessingFilter.doFilterHttp(AnonymousProcessingFilter.java:105)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter.doFilterHttp(SecurityContextHolderAwareRequestFilter.java:91)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.ui.preauth.AbstractPreAuthenticatedProcessingFilter.doFilterHttp(AbstractPreAuthenticatedProcessingFilter.java:69)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:175)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:236)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:525)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
    at java.lang.Thread.run(Thread.java:619)

Highlighting

at jaci.web.ProcessingJobController.setSessionAttribute(ProcessingJobController.java:223)
at jaci.web.ProcessingJobController.setSessionWeb(ProcessingJobController.java:219)
at jaci.web.ProcessingJobController.initSessionJobAndWeb(ProcessingJobController.java:183)
at jaci.web.ProcessingJobController.handlePost(ProcessingJobController.java:91)

For this controller

@Controller
@RequestMapping("/processingJob.*")
public class ProcessingJobController {

    private static final String WEB_SESSION_ATTRIBUTE = "web";

    private static final Logger LOGGER = LoggerFactory.getLogger(ProcessingJobController.class);

    @Autowired
    private PrinterService printerService;

    @Autowired
    private WebService webService;

    @Autowired
    private UserService userService;

    @RequestMapping(method = RequestMethod.GET)
    public ModelAndView deleteMostRecentRange(final HttpServletRequest request) {
        LOGGER.debug(
                "Received a request to delete {} from {}.",
                this.lastCheckRangeOnJob(this.sessionJob(request)),
                this.sessionJob(request));
        Map<String, Object> processingJobModel = new HashMap<String, Object>();
        this.printerService.deleteMostRecentRange(this.sessionJob(request));
        return this.processingJobModelAndView(request, processingJobModel);
    }

    //FIXME Awful, awful, awful, awful, awful, awful, awful, awful, awful TAV
    @RequestMapping(method = RequestMethod.POST)
    public ModelAndView handlePost(
            @RequestParam(
                    value = JOB_SESSION_ATTRIBUTE,
                    required = false)
                final Long jobId,
            @RequestParam(
                    value = WEB_SESSION_ATTRIBUTE,
                    required = false)
                final Long webId,
            @RequestParam(
                    value = "new-end-icn",
                    required = false)
                final String newEndIcn,
            @RequestParam(
                    value = "rangeType",
                    required = false)
                final String newRangeType,
            final HttpServletRequest request) {

        Map<String, Object> processingJobModel = new HashMap<String, Object>();

        if (this.isInitialRequest(request)) {
            this.initSessionJobAndWeb(jobId, webId, request);
        } else if (this.isGetAvailableWebsRequest(jobId, webId, newEndIcn)) {
            this.setAvailableWebsInModel(processingJobModel);
        } else if (this.isChangeWebRequest(jobId, webId, newEndIcn)) {
            this.setSessionWeb(request, this.webService.getWeb(webId));
        } else if (this.isAddRangeRequest(jobId, webId, newEndIcn, newRangeType)) {
            this.addCheckRangeToJob(newEndIcn, newRangeType, request, processingJobModel);
        }

        return this.processingJobModelAndView(request, processingJobModel);

    }

    private void initSessionJobAndWeb(final Long jobId, final Long webId, final HttpServletRequest request) {
        this.setSessionJob(request, this.printerService.getJobForProcessing(jobId));
        this.setSessionWeb(request, this.webService.getWeb(webId));
    }

    private void setSessionWeb(final HttpServletRequest request, final Web web) {
        this.setSessionAttribute(request, WEB_SESSION_ATTRIBUTE, web);
    }

    private void setSessionAttribute(final HttpServletRequest request, final String sessionAttribute, final Object value) {
        LOGGER.debug("Received a request to set Session {} to {}", sessionAttribute, value);
        request.getSession().setAttribute(sessionAttribute, value);
    }

Given that, how can I write a test to isolate that failure and ensure that I don't break it in the future. Here's what I have so far.

package jaci.web;

import static org.junit.Assert.assertNotNull;
import jaci.service.WebService;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;

@ContextConfiguration(locations = { "/applicationContext-data.xml", "/applicationContext-service.xml" })
public class ProcessingJobControllerTest
extends AbstractTransactionalJUnit4SpringContextTests {

    @Autowired
    private WebService webService;

    @Test
    public void logWebToString() {
        String web = this.webService.getWeb(-19L).toString();
        assertNotNull(web);
    }

}
+2  A: 

AbstractTransactionalJUnit4SpringContextTests is nothing more than a convenience for tests that want to do stuff inside a transaction. There's no reason why you can't take a more manual approach.

Your test could have itself injected with the PlatformTransactionManager, which is can then call programmatically (e.g. using TransactionTemplate). The semantics would be just the same as described in the docs for programmatic transactions in live code.

So your test can begin a transaction, do some work, commit/rollback, then carry on doing additional work in order to exercise the the lazy-init path.

skaffman
A: 

I've had success doing this in the past by getting access to the hiberate session and doing a manual .flush(); and .evict();

I actually used it so much that I put it into a Testing Superclass method called clearSession()

But from your code I don't see a simple way to get access to the session

walnutmon