В веб-приложении на основе Spring bean-объекты могут быть привязаны к «сеансу» пользователя. По сути, это означает, что изменения состояния bean-объекта области видимости видны только в области сеанса пользователя.
Цель этой записи — просто выделить способ, предоставленный Spring Test MVC, для тестирования компонентов, которые имеют в качестве зависимостей бины сессионной области.
Рассмотрим пример из ссылочных документов Spring класса UserPreferences, в котором, скажем, указан timeZoneId пользователя:
|
01
02
03
04
05
06
07
08
09
10
11
|
@Component@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)public class UserPreferences { private String timeZoneId="default"; public String getTimeZoneId() { return timeZoneId; } public void setTimeZoneId(String timeZoneId) { this.timeZoneId = timeZoneId; }} |
Здесь область видимости помечена как «сессия», а proxyMode явно указан как TARGET_CLASS, чтобы инструктировать Spring для создания прокси CGLIB (поскольку UserPreferences не реализует какой-либо другой интерфейс).
Теперь рассмотрим контроллер, использующий этот bean-объект сессионной области в качестве зависимости:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
@Controllerpublic class HomeController { @Autowired private UserPreferences userPreferences; @RequestMapping(value="/setuserprefs") public String setUserPrefs(@RequestParam("timeZoneId") String timeZoneId, Model model) { userPreferences.setTimeZoneId(timeZoneId); model.addAttribute("timeZone", userPreferences.getTimeZoneId()); return "preferences"; } @RequestMapping(value="/gotopage") public String goToPage(@RequestParam("page") String page, Model model) { model.addAttribute("timeZone", userPreferences.getTimeZoneId()); return page; }} |
Здесь есть два метода контроллера, в первом методе пользовательское предпочтение установлено, и во втором методе пользовательское предпочтение прочитано. Если bean-объект в области сеанса работает чисто, то вызов «/ setuserprefs» в пользовательском сеансе должен установить предпочтение timeZoneId в bean-компоненте UserPreferences, а другой вызов «/ gotopage» в том же сеансе должен успешно извлечь ранее установленное предпочтение.
Проверить это просто с помощью поддержки тестирования Spring MVC, которая теперь поставляется с модулем Spring-test.
Тест выглядит примерно так:
Сначала определение bean-компонента для теста с использованием Spring Java Configuration:
|
1
2
3
4
|
@Configuration@EnableWebMvc@ComponentScan({"scope.model","scope.services", "scope.web"})public class ScopeConfiguration {} |
и тест:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.mock.web.MockHttpSession;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import org.springframework.test.context.web.WebAppConfiguration;import org.springframework.test.web.servlet.MockMvc;import org.springframework.web.context.WebApplicationContext;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=ScopeConfiguration.class)@WebAppConfigurationpublic class ScopeConfigurationTest { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void setup() { this.mockMvc = webAppContextSetup(this.wac).build(); } @Test public void testSessionScope() throws Exception { MockHttpSession mocksession = new MockHttpSession(); this.mockMvc.perform( get("/setuserprefs?timeZoneId={timeZoneId}", "US/Pacific") .session(mocksession)) .andExpect(model().attribute("timeZone", "US/Pacific")); this.mockMvc.perform( get("/gotopage?page={page}", "home") .session(mocksession)) .andExpect(model().attribute("timeZone", "US/Pacific")); this.mockMvc.perform( get("/gotopage?page={page}", "home") .session(new MockHttpSession())) .andExpect(model().attribute("timeZone", "default")); }} |
В тесте сначала создается MockHttpSession для имитации пользовательского сеанса. Последующие два запроса выполняются в контексте этого фиктивного сеанса, поэтому ожидается, что один и тот же компонент UserPreferences будет виден в контроллере, который утверждается в тесте. В третьем запросе создается новый сеанс, и на этот раз в контроллере виден другой бин UserPreferences, который утверждается поиском другого атрибута.
Это демонстрирует чистый способ тестирования bean-компонентов сессионной области с использованием поддержки Spring test MVC.