javascript
spring框架mvc框架_Spring的MVC测试框架入门–第1部分
spring框架mvc框架
最新推出的主要Spring框架是Spring MVC測試框架,Spring Guys聲稱它是“一流的JUnit支持,可通過流暢的API測試客戶端和服務(wù)器端Spring MVC代碼” 1 。 在這個(gè)博客以及下一個(gè)博客中,我將看一看Spring的MVC測試框架,并將其應(yīng)用于我現(xiàn)有的一些示例代碼中,以弄清它是否能如其所愿。
該API通過兩種設(shè)置服務(wù)器端測試的方式進(jìn)行了設(shè)計(jì)。 首先,它們帶有Spring上下文文件,其次,以編程方式?jīng)]有上下文文件。 Spring的Guy將該程序化方法稱為“獨(dú)立”模式。
以編程方式設(shè)置測試似乎更類似于單元測試,并且最好用于對特定的控制器類進(jìn)行獨(dú)立于其協(xié)作者的單元測試。 另一方面,加載Spring上下文文件的操作實(shí)際上是集成測試,并且更適合端到端測試。
您可以在此處找到有關(guān)測試技術(shù)的博客的完整列表。
如果您像我一樣,那么您已經(jīng)在使用現(xiàn)有的框架(例如Mockito或Easymock)來測試您的控制器。 通常的Mockito / Easymock方法是實(shí)例化您的控制器,注入模擬或存根依賴性,然后調(diào)用被測方法,注意返回值或驗(yàn)證模擬方法調(diào)用。
Spring Mvc Test框架采用了與其他模擬框架不同的方法,因?yàn)樗虞d了Spring DispatcherServlet以模擬Web容器的操作。 然后將被測試的控制器加載到Spring上下文中,然后像在“現(xiàn)實(shí)生活中”那樣,由DispatcherServlet訪問。
這種方法的好處是,它允許您將控制器作為控制器而不是POJO進(jìn)行測試。 這意味著將處理并考慮控制器的注釋,執(zhí)行驗(yàn)證并以正確的順序調(diào)用方法。
您是否同意這種方法,并取決于您對測試技術(shù)的看法。 如果您認(rèn)為應(yīng)該將測試的每個(gè)類/方法都隔離到第n個(gè)級(jí)別,并且每個(gè)測試都應(yīng)完全原子化,那么這可能不適合您。 如果您比較實(shí)用,并且可以將測試控制器的好處看作是……一個(gè)控制器,那么此框架可能是您感興趣的。
與Mockito和Easymock的方法有所不同,缺點(diǎn)是代碼看起來與這些較老的,更成熟的技術(shù)不同。 它在很大程度上依賴于構(gòu)建器模式來構(gòu)造匹配器,請求構(gòu)建器和處理程序,一旦掌握了這些,這一切就變得很有意義。 我懷疑使用構(gòu)建器模式的動(dòng)機(jī)是為了簡化模擬HttpServletRequest的設(shè)置以及對模擬HttpServletResponse對象的詢問,這從定義HttpServletResponse可能非常棘手。
在此博客中,我將看一下Spring API的編程/獨(dú)立技術(shù),并將其與類似的基于Mockito的單元測試進(jìn)行比較。
為了加快處理速度,我使用了Blue Peter方法“這是我之前準(zhǔn)備的方法”,并從我的Facebook博客中獲取了FacebookPostsController ,我將為此編寫兩個(gè)單元測試類:第一個(gè)使用Mockito,另一個(gè)使用Spring Mvc測試API。
控制器代碼如下:
@Controller public class FacebookPostsController { private static final Logger logger = LoggerFactory .getLogger(FacebookPostsController.class); @Autowired private SocialContext socialContext; @RequestMapping(value = "posts", method = RequestMethod.GET) public String showPostsForUser(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { String nextView; if (socialContext.isSignedIn(request, response)) { List<Post> posts = retrievePosts(); model.addAttribute("posts", posts); nextView = "show-posts"; } else { nextView = "signin"; } return nextView; } private List<Post> retrievePosts() { Facebook facebook = socialContext.getFacebook(); FeedOperations feedOps = facebook.feedOperations(); List<Post> posts = feedOps.getHomeFeed(); logger.info("Retrieved " + posts.size() + " posts from the Facebook authenticated user"); return posts; } }我不打算講這段代碼的背景,因?yàn)樗梢栽贔acebook博客中找到 。 但是,總而言之,Facebook示例應(yīng)用程序訪問用戶的Facebook帳戶并在示例應(yīng)用程序中顯示其新聞提要。 為此, FacebookPostsController檢查SocialContext類,以確定用戶是否已登錄其Facebook帳戶。 如果用戶登錄到其Facebook帳戶,則控制器將檢索用戶的帖子并將其添加到模型中以進(jìn)行顯示。 另一方面,如果用戶未登錄,則將他們定向到登錄頁面。
 兩個(gè)單元測試類中的每一個(gè)都將包含三個(gè)公共方法: 
 我將依次檢查setup() , testShowPostsForUser_user_is_not_signed_in和testShowPostsForUser_user_is_signed_in 。 
如您所料,測試testShowPostsForUser_user_is_not_signed_in和testShowPostsForUser_user_is_signed_in用于測試用戶登錄和未登錄其Facebook帳戶的情況。
“標(biāo)準(zhǔn)” Mockito測試
@Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); instance = new FacebookPostsController(); ReflectionTestUtils.setField(instance, "socialContext", socialContext); }設(shè)置代碼相當(dāng)簡單,包含三個(gè)簡單步驟:
testShowPostsForUser_user_is_not_signed_in方法將模擬的SocialContext配置為在調(diào)用其isSignedIn()方法時(shí)返回false 。 這意味著剩下要做的就是斷言showPostsForUser(...)方法返回"signin"將用戶定向到登錄頁面。
@Test public void testShowPostsForUser_user_is_signed_in() throws Exception { when(socialContext.isSignedIn(request, response)).thenReturn(true); when(socialContext.getFacebook()).thenReturn(facebook); when(facebook.feedOperations()).thenReturn(feedOps); List<Post> posts = Collections.emptyList(); when(feedOps.getHomeFeed()).thenReturn(posts); String result = instance.showPostsForUser(request, response, model); verify(model).addAttribute("posts", posts); assertEquals("show-posts", result); }testShowPostsForUser_user_is_signed_in稍微復(fù)雜一些。 在將模擬的SocialContext配置為在調(diào)用其isSignedIn()方法時(shí)返回true ,還有另外四行代碼可確保從模擬Facebook提要中返回posts列表并將其添加到模擬Model 。 調(diào)用showPostsForUser(...)之后,需要完成兩個(gè)附加步驟:驗(yàn)證模擬Model包含posts列表,并斷言showPostsForUser(...)的返回值為"show-posts" 。
接下來,Spring MVC Test框架代碼; 但是,在開始之前,您需要將以下依賴項(xiàng)添加到POM文件:
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${org.springframework-version}</version><scope>test</scope></dependency>Spring MVC測試
Spring MVC測試框架版本運(yùn)行相同的兩個(gè)測試,但是方式不同……
@Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); FacebookPostsController instance = new FacebookPostsController(); ReflectionTestUtils.setField(instance, "socialContext", socialContext); mockMvc = MockMvcBuilders.standaloneSetup(instance).build(); } 如果看一下上面的代碼,就可以看到,就setup(...)而言,它看起來與上面的直接Mockito代碼非常相似。 像基于Mockito的測試一樣,第一步是使用初始化模擬對象 
 MockitoAnnotations.initMocks(this) ,然后創(chuàng)建一個(gè)FacebookPostsController的新實(shí)例,將模擬的SocialContext注入其中。 但是,這一次, FacebookPostsController狀態(tài)已降級(jí)為局部變量,因?yàn)樵O(shè)置的重點(diǎn)是創(chuàng)建Spring的MockMvc實(shí)例,該實(shí)例用于執(zhí)行測試。 該mockMvc是通過調(diào)用創(chuàng)建MockMvcBuilders.standaloneSetup(instance).build()其中instance是FacebookPostsController對象,我們正在測試。 
 與Mockito版本類似, testShowPostsForUser_user_is_not_signed_in方法將模擬的SocialContext配置為在調(diào)用其isSignedIn()方法時(shí)返回false 。 這次,下一步是使用靜態(tài)方法創(chuàng)建一個(gè)稱為MockHttpServletRequestBuilder東西。 
 MockMvcRequestBuilders.get(...)和構(gòu)建器模式。 這被傳遞到mockMVC.perform(...)方法中,在此方法中,該方法用于創(chuàng)建MockHttpServletRequest對象,該對象用于定義測試的起點(diǎn)。 在此測試中,我要做的只是傳遞"/posts" URL并將輸入設(shè)置為“ any”媒體類型。 您可以使用諸如contentType() , contextPath() , cookie()等方法配置許多其他請求對象屬性。有關(guān)更多信息,請查看Spring Javadoc中的MockHttpServletRequest 
mockMvc.perform()方法返回一個(gè)ResultActions對象。 這似乎是實(shí)際MvcResult的包裝。 ResultsActions是一個(gè)便捷對象,用于以與JUnit的assertEquals(...)或Mockito的verify(..)方法相同的方式聲明測試結(jié)果。 在這種情況下,我正在檢查結(jié)果Http狀態(tài)是否正常(即200),并且下一個(gè)視圖將"signin" 。
此測試與僅Mockito版本之間的區(qū)別在于,您不是直接測試對測試實(shí)例的方法調(diào)用的結(jié)果; 您正在測試方法調(diào)用生成的HttpServletResponse對象。
@Test public void testShowPostsForUser_user_is_signed_in() throws Exception { HttpServletRequest request = anyObject(); HttpServletResponse response = anyObject(); when(socialContext.isSignedIn(request, response)).thenReturn(true); when(socialContext.getFacebook()).thenReturn(facebook); when(facebook.feedOperations()).thenReturn(feedOps); List<Post> posts = Collections.emptyList(); when(feedOps.getHomeFeed()).thenReturn(posts); mockMvc.perform(get("/posts").accept(MediaType.ALL)).andExpect(status().isOk()) .andExpect(model().attribute("posts", posts)) .andExpect(view().name("show-posts")); }testShowPostsForUser_user_is_signed_in方法的Spring Test版本與Mockito版本非常相似,該測試是通過將SocialContext.isSignedIn()方法配置為返回true以及feedOps.getHomeFeed()配置為返回posts列表來準(zhǔn)備測試的。 此方法的Spring Mvc Test部分與上述testShowPostsForUser_user_is_not_signed_in版本幾乎相同,除了這次它使用andExpect(view().name("show-posts")檢查下一個(gè)視圖名稱為"show-posts"而不是"sign-in" andExpect(view().name("show-posts")我在這里使用的代碼樣式與我在上面使用的樣式有所不同,并且是Spring的Guy偏愛的樣式。如果您能在Github上找到更多這種樣式的示例,持有Spring MVC Showcase應(yīng)用。
那么,您可以從此比較中得出什么結(jié)論? 公平地說,這不是真正的比較– Spring MVC Test API在建立標(biāo)準(zhǔn)Mockito技術(shù)的基礎(chǔ)上,采用了不同的方法,創(chuàng)建了一個(gè)框架,旨在僅在其本機(jī)運(yùn)行時(shí)環(huán)境的模型中對Spring MVC控制器進(jìn)行測試。 。
這對您是否有用,我會(huì)讓您決定。 它確實(shí)具有將控制器視為控制器而不是POJO的優(yōu)點(diǎn),這意味著它們已經(jīng)過更徹底的測試。 從個(gè)人的角度來看,我喜歡加載Spring配置文件并將其用于集成測試的想法,這將在我的下一個(gè)博客中介紹。
- 1請參閱: http : //static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/testing.html#spring-mvc-test-framework
- 該博客的代碼可在GitHub上找到: https : //github.com/roghughe/captaindebug/tree/master/facebook
翻譯自: https://www.javacodegeeks.com/2013/07/getting-started-with-springs-mvc-test-framework-part-1.html
spring框架mvc框架
總結(jié)
以上是生活随笔為你收集整理的spring框架mvc框架_Spring的MVC测试框架入门–第1部分的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 毅力的近义词 毅力有哪些近义词
- 下一篇: 多久一次用英语怎么说 多久一次用英语表达
