Question

We have singleton controllers like

@Controller
class C {
  @Autowire MyObject obj;
  public void doGet() {
    // do something with obj
  }
}

MyObject is created in a filter/interceptor and is put into HttpServletRequest attributes. Then it's obtained in @Configuration:

@Configuration
class Config {
  @Autowire
  @Bean @Scope("request")
  MyObject provideMyObject(HttpServletRequest req) {
      return req.getAttribute("myObj");
  }
}

Everything works well in main code, but not in testing: when I run it from an integration test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/web-application-config_test.xml")
class MyTest {
    @Autowired
    C controller;

    @Test
    void test() {
       // Here I can easily create "new MockHttpServletRequest()"
       // and set MyObject to it, but how to make Spring know about it?
       c.doGet();
    }
}

it complains that NoSuchBeanDefinitionException: No matching bean of type [javax.servlet.http.HttpServletRequest]. (At first, it complained about request scope is not active, but I resolved it using CustomScopeConfigurer with SimpleThreadScope as suggested here).

How to let Spring injection know about my MockHttpServletRequest? Or directly MyObject?

Was it helpful?

Solution

Workarounded temporarily, but it looks like the right approach: in Config, instead of req.getAttribute("myObj"), write

RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
return (MyObject) requestAttributes.getAttribute("myObj", RequestAttributes.SCOPE_REQUEST);

so it does not need a HttpServletRequest instance anymore. And fill it in test:

MockHttpServletRequest request = new MockHttpServletRequest();
request.setAttribute("myObj", /* set up MyObject instance */)
RequestContextHolder.setRequestAttributes(new ServletWebRequest(request));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top