简体   繁体   中英

Mocking/autowiring beans with Spring 3.1.x and MockMvc

I'm using Spring 3.1.4, and trying to write some integration tests around our authentication with MockMvc.

One of the root problems I'm running into is that because I'm not using Spring 3.2, I can't @Autowire a WebApplicationContext object in my test, and thus can't use the MockMvcBuilders.webApplicationContextSetup() , so I'm using the xmlConfigSetup instead.

I seem to have hit a path with multiple forks, neither of which solve all my problems.

I have things configured like so:

@ContextConfiguration(locations = {
        "classpath:/test-applicationContext.security.xml",
        "classpath:/test-mvc-dispatcher-servlet.xml"
})
@RunWith(SpringJUnit4ClassRunner.class)
public class SecurityTests extends AbstractJUnit4SpringContextTests {

    public static final String[] CONTEXT_CONFIG = {
            "classpath:/test-applicationContext.security.xml", "classpath:/test-mvc-dispatcher-servlet.xml"
    };

    @Autowired
    private Filter springSecurityFilterChain;

    @Before
    public void setUp() {
        ContextMockMvcBuilder xmlConfigSetup = MockMvcBuilders.xmlConfigSetup(CONTEXT_CONFIG);
        this.mockMvc = xmlConfigSetup.addFilters(springSecurityFilterChain).build();
    }

The advantage here is that my springSecurityFilterChain is @Autowired , making it easy to provide to addFilters() . The disadvantage is that any other autowired beans are different instances than the ones in my MockMvc configuration, since I'm essentially building my servlet context twice. This means that if I autowire a UserDetailsService and tweak it in my integration test (add a user "bob"), the MockMvc instance doesn't have it.

Option 1: Using the above config, can I access any of the beans inside the MockMvc instance? I haven't found a way, which makes "prepping" for any integration test impossible.

Option 2: Remove the @ContextConfiguration and just let the MockMvc drive the tests. This seems cleaner, but I can't figure out how to then create/inject a Spring Security filter chain - as it's no longer autowired. ( None of my beans are - which makes accessing other critical beans like the UserDetailsService problematic as well.)

Option 3: Can I rig up a WebApplicationContext manually that wraps from the applicationContext in the AbstractJUnit4SpringContextTests superclass, and provide this to the MockMvcBuilders.webApplicationContextSetup() method? This has the advantage of not needing two separate servlet contexts, but it seems especially hacky to build this up manually when I don't really have one - and I'm not sure how to integrate the Spring Security filter chain into this either.

I'm looking for advice on which (if any) of the above options are most feasible, and how to accomplish them.

Unfortunately upgrading to a newer version of Spring is not an option.

This post from the Spring team proposes a way to inject the WebApplicationContext into JUnit tests. They use a custom context loader specifically implemented for running integration tests, in addition to specifying the configuration location. The trouble is that their context loader depends on a class that is no longer available in any of the Spring repositories. However, it can be derived from some of the Spring MVC Test Samples .

Step 1 : Create a custom context loader

class TestWebContextLoader extends AbstractContextLoader { ... }

This context loader will be used to load your Spring configuration files.

Step 2 : Use the custom loader to load the Spring configuration files.

Change

@ContextConfiguration(locations = {
    "classpath:/test-applicationContext.security.xml",
    "classpath:/test-mvc-dispatcher-servlet.xml" })

to

@ContextConfiguration(loader = TestWebContextLoader.class,
    locations = {
    "classpath:/test-applicationContext.security.xml",
    "classpath:/test-mvc-dispatcher-servlet.xml" })

Step 3 : Inject WebApplicationContext into your JUnit tests

public class SecurityTests extends AbstractJUnit4SpringContextTests {
  @Autowired
  private WebApplicationContext webApplicationContext;
}

Step 4 : Build a mock using the injected WebApplicationContext

public class SecurityTests extends AbstractJUnit4SpringContextTests {
  @Autowired
  private WebApplicationContext webApplicationContext;

  @Before
  public void setUp() {
    MockMvc mock = MockMvcBuilders.webApplicationContextSetup(webApplicationContext).build();
  }
}

I have created a sample application that demonstrates the concept and where the context loads successfully.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM