Spring 从早期就支持请求域和会话域的 Bean,你可以通过以下步骤测试你的请求域和会话域 Bean。
- 通过用 @WebAppConfiguration 注释你的测试类,确保为你的测试加载 WebApplicationContext。
- 注入模拟请求或会话到你的测试实例中,并适当地准备你的测试夹具。
- 调用你从配置的 WebApplicationContext 中获取的 Web 组件(使用依赖性注入)。
- 对模拟程序进行断言。
下一个代码片断显示了登录用例的 XML 配置。请注意,userService Bean 对请求范围的 loginAction Bean 有依赖性。另外,LoginAction 是通过使用 SpEL 表达式来实例化的,它从当前的 HTTP 请求中获取用户名和密码。在我们的测试中,我们想通过 TestContext 框架管理的 mock 来配置这些请求参数。下面的列表显示了这个用例的配置。
Request 作用域的 bean 配置
<beans>
<bean id="userService" class="com.example.SimpleUserService"
c:loginAction-ref="loginAction"/>
<bean id="loginAction" class="com.example.LoginAction"
c:username="#{request.getParameter('user')}"
c:password="#{request.getParameter('pswd')}"
scope="request">
<aop:scoped-proxy/>
</bean>
</beans>
在 RequestScopedBeanTests 中,我们将 UserService(即被测对象)和 MockHttpServletRequest 都注入我们的测试实例中。在我们的 requestScope()
测试方法中,我们通过在提供的 MockHttpServletRequest 中设置请求参数来设置我们的测试夹具。当 loginUser()
方法在我们的 userService上被调用时,我们保证用户服务可以访问当前 MockHttpServletRequest(也就是我们刚刚设置参数的那个)的请求范围 loginAction。然后我们可以根据已知的用户名和密码的输入,对结果执行断言。下面的列表显示了如何做到这一点。
@SpringJUnitWebConfig
class RequestScopedBeanTests {
@Autowired UserService userService;
@Autowired MockHttpServletRequest request;
@Test
void requestScope() {
request.setParameter("user", "enigma");
request.setParameter("pswd", "$pr!ng");
LoginResults results = userService.loginUser();
// assert results
}
}
例子全部代码
前面文章都是讲解概念,没有代码例子,下面是这个例子的全部代码
测试类
package cn.mrcode.study.springdocsread.test;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import cn.mrcode.study.springdocsread.web.LoginResults;
import cn.mrcode.study.springdocsread.web.UserService;
@SpringJUnitWebConfig(locations = "classpath:test.xml")
class RequestScopedBeanTests {
@Autowired
UserService userService;
@Autowired
MockHttpServletRequest request;
@Test
void requestScope() {
request.setParameter("user", "enigma");
request.setParameter("pswd", "$pr!ng");
LoginResults results = userService.loginUser();
// assert results
}
}
这个测试用例,mock 了一个 request 对象,然后代码中可以使用这个对象(在 xml 中初始化 loginAction 的时候使用的)
bean 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- c: 命名空间是构造函数,ref 是用引用名称方式注入 -->
<bean id="userService" class="cn.mrcode.study.springdocsread.web.SimpleUserService"
c:loginAction-ref="loginAction"/>
<bean id="loginAction" class="cn.mrcode.study.springdocsread.web.LoginAction"
c:username="#{request.getParameter('user')}"
c:password="#{request.getParameter('pswd')}"
scope="request">
<aop:scoped-proxy/>
</bean>
</beans>
下面是相关的辅助类
package cn.mrcode.study.springdocsread.web;
/**
* @author mrcode
*/
public class LoginAction {
private String username;
private String password;
public LoginAction(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package cn.mrcode.study.springdocsread.web;
/**
* @author mrcode
*/
public class LoginResults {
public String username;
public String password;
}
package cn.mrcode.study.springdocsread.web;
/**
* @author mrcode
*/
public class SimpleUserService implements UserService {
private LoginAction loginAction;
public SimpleUserService(LoginAction loginAction) {
this.loginAction = loginAction;
}
@Override
public LoginResults loginUser() {
final LoginResults loginResults = new LoginResults();
loginResults.username = loginAction.getUsername();
loginResults.password = loginAction.getPassword();
return loginResults;
}
}
package cn.mrcode.study.springdocsread.web;
/**
* @author mrcode
*/
public interface UserService {
LoginResults loginUser();
}
Session 作用域的 bean 配置
下面的代码片段与我们之前看到的 request 域 Bean 的代码片段相似。然而,这一次,userService Bean session 作用域 的 userPreferences Bean 有依赖性。请注意,UserPreferences Bean 是通过使用一个 SpEL 表达式来实例化的,该表达式从当前的 HTTP 会话中检索出主题。在我们的测试中,我们需要在 TestContext 框架所管理的模拟会话中配置一个主题。下面的例子展示了如何做到这一点:
<beans>
<bean id="userService" class="com.example.SimpleUserService"
c:userPreferences-ref="userPreferences" />
<bean id="userPreferences" class="com.example.UserPreferences"
c:theme="#{session.getAttribute('theme')}"
scope="session">
<aop:scoped-proxy/>
</bean>
</beans>
在 SessionScopedBeanTests 中,我们将 UserService 和 MockHttpSession 注入到我们的测试实例。在我们的 sessionScope()
测试方法中,我们通过在提供的 MockHttpSession 中设置预期的主题属性来设置我们的测试夹具。当 processUserPreferences()
方法在我们的userService上被调用时,我们确信用户服务可以访问当前 MockHttpSession 的会话范围 userPreferences,并且我们可以根据配置的主题对结果进行断言。下面的例子展示了如何做到这一点。
@SpringJUnitWebConfig
class SessionScopedBeanTests {
@Autowired UserService userService;
@Autowired MockHttpSession session;
@Test
void sessionScope() throws Exception {
session.setAttribute("theme", "blue");
Results results = userService.processUserPreferences();
// assert results
}
}