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。然后我们可以根据已知的用户名和密码的输入,对结果执行断言。下面的列表显示了如何做到这一点。
@SpringJUnitWebConfigclass RequestScopedBeanTests {@Autowired UserService userService;@Autowired MockHttpServletRequest request;@Testvoid 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 {@AutowiredUserService userService;@AutowiredMockHttpServletRequest request;@Testvoid 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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://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;}@Overridepublic 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,并且我们可以根据配置的主题对结果进行断言。下面的例子展示了如何做到这一点。
@SpringJUnitWebConfigclass SessionScopedBeanTests {@Autowired UserService userService;@Autowired MockHttpSession session;@Testvoid sessionScope() throws Exception {session.setAttribute("theme", "blue");Results results = userService.processUserPreferences();// assert results}}
