Spring 从早期就支持请求域和会话域的 Bean,你可以通过以下步骤测试你的请求域和会话域 Bean。

  • 通过用 @WebAppConfiguration 注释你的测试类,确保为你的测试加载 WebApplicationContext。
  • 注入模拟请求或会话到你的测试实例中,并适当地准备你的测试夹具。
  • 调用你从配置的 WebApplicationContext 中获取的 Web 组件(使用依赖性注入)。
  • 对模拟程序进行断言。

下一个代码片断显示了登录用例的 XML 配置。请注意,userService Bean 对请求范围的 loginAction Bean 有依赖性。另外,LoginAction 是通过使用 SpEL 表达式来实例化的,它从当前的 HTTP 请求中获取用户名和密码。在我们的测试中,我们想通过 TestContext 框架管理的 mock 来配置这些请求参数。下面的列表显示了这个用例的配置。

Request 作用域的 bean 配置

  1. <beans>
  2. <bean id="userService" class="com.example.SimpleUserService"
  3. c:loginAction-ref="loginAction"/>
  4. <bean id="loginAction" class="com.example.LoginAction"
  5. c:username="#{request.getParameter('user')}"
  6. c:password="#{request.getParameter('pswd')}"
  7. scope="request">
  8. <aop:scoped-proxy/>
  9. </bean>
  10. </beans>

在 RequestScopedBeanTests 中,我们将 UserService(即被测对象)和 MockHttpServletRequest 都注入我们的测试实例中。在我们的 requestScope()测试方法中,我们通过在提供的 MockHttpServletRequest 中设置请求参数来设置我们的测试夹具。当 loginUser()方法在我们的 userService上被调用时,我们保证用户服务可以访问当前 MockHttpServletRequest(也就是我们刚刚设置参数的那个)的请求范围 loginAction。然后我们可以根据已知的用户名和密码的输入,对结果执行断言。下面的列表显示了如何做到这一点。

  1. @SpringJUnitWebConfig
  2. class RequestScopedBeanTests {
  3. @Autowired UserService userService;
  4. @Autowired MockHttpServletRequest request;
  5. @Test
  6. void requestScope() {
  7. request.setParameter("user", "enigma");
  8. request.setParameter("pswd", "$pr!ng");
  9. LoginResults results = userService.loginUser();
  10. // assert results
  11. }
  12. }

例子全部代码

前面文章都是讲解概念,没有代码例子,下面是这个例子的全部代码

测试类

  1. package cn.mrcode.study.springdocsread.test;
  2. import org.junit.jupiter.api.Test;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.mock.web.MockHttpServletRequest;
  5. import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
  6. import cn.mrcode.study.springdocsread.web.LoginResults;
  7. import cn.mrcode.study.springdocsread.web.UserService;
  8. @SpringJUnitWebConfig(locations = "classpath:test.xml")
  9. class RequestScopedBeanTests {
  10. @Autowired
  11. UserService userService;
  12. @Autowired
  13. MockHttpServletRequest request;
  14. @Test
  15. void requestScope() {
  16. request.setParameter("user", "enigma");
  17. request.setParameter("pswd", "$pr!ng");
  18. LoginResults results = userService.loginUser();
  19. // assert results
  20. }
  21. }

这个测试用例,mock 了一个 request 对象,然后代码中可以使用这个对象(在 xml 中初始化 loginAction 的时候使用的)

bean 配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xmlns:c="http://www.springframework.org/schema/c"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. https://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
  9. <!-- c: 命名空间是构造函数,ref 是用引用名称方式注入 -->
  10. <bean id="userService" class="cn.mrcode.study.springdocsread.web.SimpleUserService"
  11. c:loginAction-ref="loginAction"/>
  12. <bean id="loginAction" class="cn.mrcode.study.springdocsread.web.LoginAction"
  13. c:username="#{request.getParameter('user')}"
  14. c:password="#{request.getParameter('pswd')}"
  15. scope="request">
  16. <aop:scoped-proxy/>
  17. </bean>
  18. </beans>

下面是相关的辅助类

  1. package cn.mrcode.study.springdocsread.web;
  2. /**
  3. * @author mrcode
  4. */
  5. public class LoginAction {
  6. private String username;
  7. private String password;
  8. public LoginAction(String username, String password) {
  9. this.username = username;
  10. this.password = password;
  11. }
  12. public String getUsername() {
  13. return username;
  14. }
  15. public void setUsername(String username) {
  16. this.username = username;
  17. }
  18. public String getPassword() {
  19. return password;
  20. }
  21. public void setPassword(String password) {
  22. this.password = password;
  23. }
  24. }
  1. package cn.mrcode.study.springdocsread.web;
  2. /**
  3. * @author mrcode
  4. */
  5. public class LoginResults {
  6. public String username;
  7. public String password;
  8. }
  1. package cn.mrcode.study.springdocsread.web;
  2. /**
  3. * @author mrcode
  4. */
  5. public class SimpleUserService implements UserService {
  6. private LoginAction loginAction;
  7. public SimpleUserService(LoginAction loginAction) {
  8. this.loginAction = loginAction;
  9. }
  10. @Override
  11. public LoginResults loginUser() {
  12. final LoginResults loginResults = new LoginResults();
  13. loginResults.username = loginAction.getUsername();
  14. loginResults.password = loginAction.getPassword();
  15. return loginResults;
  16. }
  17. }
  1. package cn.mrcode.study.springdocsread.web;
  2. /**
  3. * @author mrcode
  4. */
  5. public interface UserService {
  6. LoginResults loginUser();
  7. }

Session 作用域的 bean 配置

下面的代码片段与我们之前看到的 request 域 Bean 的代码片段相似。然而,这一次,userService Bean session 作用域 的 userPreferences Bean 有依赖性。请注意,UserPreferences Bean 是通过使用一个 SpEL 表达式来实例化的,该表达式从当前的 HTTP 会话中检索出主题。在我们的测试中,我们需要在 TestContext 框架所管理的模拟会话中配置一个主题。下面的例子展示了如何做到这一点:

  1. <beans>
  2. <bean id="userService" class="com.example.SimpleUserService"
  3. c:userPreferences-ref="userPreferences" />
  4. <bean id="userPreferences" class="com.example.UserPreferences"
  5. c:theme="#{session.getAttribute('theme')}"
  6. scope="session">
  7. <aop:scoped-proxy/>
  8. </bean>
  9. </beans>

在 SessionScopedBeanTests 中,我们将 UserService 和 MockHttpSession 注入到我们的测试实例。在我们的 sessionScope() 测试方法中,我们通过在提供的 MockHttpSession 中设置预期的主题属性来设置我们的测试夹具。当 processUserPreferences()方法在我们的userService上被调用时,我们确信用户服务可以访问当前 MockHttpSession 的会话范围 userPreferences,并且我们可以根据配置的主题对结果进行断言。下面的例子展示了如何做到这一点。

  1. @SpringJUnitWebConfig
  2. class SessionScopedBeanTests {
  3. @Autowired UserService userService;
  4. @Autowired MockHttpSession session;
  5. @Test
  6. void sessionScope() throws Exception {
  7. session.setAttribute("theme", "blue");
  8. Results results = userService.processUserPreferences();
  9. // assert results
  10. }
  11. }