MockMVC 将测试控制器与会话范围 bean 集成
Posted
技术标签:
【中文标题】MockMVC 将测试控制器与会话范围 bean 集成【英文标题】:MockMVC Integrate test controller with session scoped bean 【发布时间】:2015-09-13 17:16:45 【问题描述】:我正在尝试集成测试 Spring Controller 方法,该方法使用注入到控制器中的 Spring 会话范围 bean。为了让我的测试通过,在我对这个控制器方法进行模拟调用之前,我必须能够访问我的会话 bean 以在其上设置一些值。问题是在我进行调用时创建了一个新的会话 bean,而不是使用我从模拟应用程序上下文中提取的那个。如何让我的控制器使用相同的 UserSession bean?
这是我的测试用例
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration("src/main/webapp")
@ContextConfiguration("file:src/main/webapp/WEB-INF/applicationContext.xml",
"file:src/main/webapp/WEB-INF/rest-servlet.xml",
"file:src/main/webapp/WEB-INF/servlet-context.xml")
public class RoleControllerIntegrationTest
@Autowired
private WebApplicationContext wac;
protected MockMvc mockMvc;
protected MockHttpSession mockSession;
@BeforeClass
public static void setupClass()
System.setProperty("runtime.environment","TEST");
System.setProperty("com.example.UseSharedLocal","true");
System.setProperty("com.example.OverridePath","src\\test\\resources\\properties");
System.setProperty("JBHSECUREDIR","C:\\ProgramData\\JBHSecure");
@Before
public void setup()
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
mockSession = new MockHttpSession(wac.getServletContext(), UUID.randomUUID().toString());
mockSession.setAttribute("jbhSecurityUserId", "TESTUSER");
@Test
public void testSaveUserRole() throws Exception
UserSession userSession = wac.getBean(UserSession.class);
userSession.setUserType(UserType.EMPLOYEE);
userSession.setAuthorizationLevel(3);
Role saveRole = RoleBuilder.buildDefaultRole();
Gson gson = new Gson();
String json = gson.toJson(saveRole);
MvcResult result = this.mockMvc.perform(
post("/role/save")
.contentType(MediaType.APPLICATION_JSON)
.content(json)
.session(mockSession))
.andExpect(status().isOk())
.andReturn();
MockHttpServletResponse response = result.getResponse();
这是我需要测试的控制器方法
@Resource(name="userSession")
private UserSession userSession;
@RequestMapping(method = RequestMethod.POST, value = "/save")
public @ResponseBody ServiceResponse<Role> saveRole(@RequestBody Role role,HttpSession session)
if(userSession.isEmployee() && userSession.getAuthorizationLevel() >= 3)
try
RoleDTO savedRole = roleService.saveRole(role,ComFunc.getUserId(session));
CompanyDTO company = userSession.getCurrentCompany();
它没有通过这一行,因为 UserSession 对象不一样 if(userSession.isEmployee() && userSession.getAuthorizationLevel() >= 3)
这是我的用户会话 bean 的声明。
@Component("userSession")
@Scope(value="session",proxyMode= ScopedProxyMode.INTERFACES)
public class UserSessionImpl implements UserSession, Serializable
private static final long serialVersionUID = 1L;
controlle 和 bean 都是在我的 applicationContext.xml 中使用组件扫描创建的
<context:annotation-config />
<!-- Activates various annotations to be detected in bean classes -->
<context:component-scan
base-package="
com.example.app.externalusersecurity.bean,
com.example.app.externalusersecurity.service,
com.example.app.externalusersecurity.wsc"/>
<mvc:annotation-driven />
【问题讨论】:
【参考方案1】:添加如下bean配置,为每个线程添加一个会话上下文
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="session">
<bean class="org.springframework.context.support.SimpleThreadScope"/>
</entry>
</map>
</property>
</bean>
Java 配置类中的等价物是下面的 bean 声明
@Bean
public CustomScopeConfigurer scopeConfigurer()
CustomScopeConfigurer configurer = new CustomScopeConfigurer();
Map<String, Object> workflowScope = new HashMap<String, Object>();
workflowScope.put("session", new SimpleThreadScope());
configurer.setScopes(workflowScope);
return configurer;
有关详细信息,请参阅 http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/beans.html#beans-factory-scopes-custom-using
【讨论】:
【参考方案2】:使用不同的 Bean definition profiles 进行测试和生产对我很有效 - 以下是基于 XML 的设置的样子:
<beans profile="production">
<bean id="userSession" class="UserSessionImpl" scope="session" >
<aop:scoped-proxy/>
</bean>
</beans>
<beans profile="test">
<bean id="userSession" class="UserSessionImpl" >
</bean>
</beans>
要为您的测试使用测试配置文件,请将@ActiveProfiles 添加到您的测试类中:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration("src/main/webapp")
@ContextConfiguration("file:src/main/webapp/WEB-INF/applicationContext.xml",
"file:src/main/webapp/WEB-INF/rest-servlet.xml",
"file:src/main/webapp/WEB-INF/servlet-context.xml")
@ActiveProfiles(profiles = "test")
public class RoleControllerIntegrationTest
[...]
【讨论】:
以上是关于MockMVC 将测试控制器与会话范围 bean 集成的主要内容,如果未能解决你的问题,请参考以下文章
如何在 MockMVC 中模拟一些 bean 而不是其他的?
spring boot 测试无法注入 TestRestTemplate 和 MockMvc
Spring MVC 测试,MockMVC:方便地将对象与 JSON 进行转换