javascript
Spring MVC测试框架入门–第1部分
最新推出的主要Spring框架是Spring MVC測試框架,Spring Guys聲稱它是“一流的JUnit支持,可通過流暢的API測試客戶端和服務(wù)器端Spring MVC代碼” 1 。 在這個博客以及下一個博客中,我將看一看Spring的MVC測試框架,并將其應(yīng)用于我現(xiàn)有的一些示例代碼中,以弄清它是否能如其所愿。
已使用兩種設(shè)置服務(wù)器端測試的方式來設(shè)計API。 首先,它們帶有Spring上下文文件,其次,以編程方式?jīng)]有上下文文件。 Spring的Guy將該程序化方法稱為“獨立”模式。
以編程方式設(shè)置測試似乎更類似于單元測試,并且最好用于對特定的控制器類進行獨立于其協(xié)作者的單元測試。 另一方面,加載Spring上下文文件的操作實際上是集成測試,并且更適合端到端測試。
您可以在此處找到有關(guān)測試技術(shù)的博客的完整列表。
如果您像我一樣,那么您已經(jīng)在使用現(xiàn)有的框架(例如Mockito或Easymock)來測試您的控制器。 通常的Mockito / Easymock方法是實例化您的控制器,注入模擬或存根依賴性,然后調(diào)用被測方法,注意返回值或驗證模擬方法調(diào)用。
Spring Mvc Test框架與其他模擬框架采用不同的方法,因為它加載Spring DispatcherServlet來模擬Web容器的操作。 然后,將被測試的控制器加載到Spring上下文中,并由DispatcherServlet對其進行訪問,就像在“現(xiàn)實生活”中一樣。
這種方法的好處是,它允許您將控制器作為控制器而不是POJO進行測試。 這意味著將處理并考慮控制器的注釋,執(zhí)行驗證并以正確的順序調(diào)用方法。
您是否同意這種方法,并取決于您對測試技術(shù)的看法。 如果您認為應(yīng)該將測試的每個類/方法都隔離到第n個級別,并且每個測試都應(yīng)完全原子化,那么這可能不適合您。 如果您比較務(wù)實,并且可以將測試控制器的好處看作是……一個控制器,那么可能會對這個框架感興趣。
與Mockito和Easymock的方法有所不同,缺點是代碼看起來與這些較舊的,已建立的技術(shù)不同。 它在很大程度上依賴于構(gòu)建器模式來構(gòu)造匹配器,請求構(gòu)建器和處理程序,一旦掌握了一切,這一切都是有道理的。 我懷疑使用構(gòu)建器模式的動機是為了簡化模擬HttpServletRequest的設(shè)置以及對模擬HttpServletResponse對象的詢問,這在定義上可能非常棘手。
在本博客中,我將看一下Spring API的編程/獨立技術(shù),并將其與類似的基于Mockito的單元測試進行比較。
為了加快處理速度,我使用了Blue Peter方法“這是我之前準備的方法”,并從我的Facebook博客中獲取了FacebookPostsController ,我將為此編寫兩個單元測試類:第一個使用Mockito,另一個使用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; } }我不打算講這段代碼的背景,因為它可以在Facebook博客中找到 。 但是,總而言之,Facebook示例應(yīng)用程序訪問用戶的Facebook帳戶并在示例應(yīng)用程序中顯示其新聞提要。 為此, FacebookPostsController檢查SocialContext類,以確定用戶是否已登錄其Facebook帳戶。 如果用戶登錄到其Facebook帳戶,則控制器將檢索用戶的帖子并將其添加到模型中以進行顯示。 另一方面,如果用戶未登錄,則將他們定向到登錄頁面。
兩個單元測試類中的每一個都將包含三個公共方法:
我將依次檢查setup() , testShowPostsForUser_user_is_not_signed_in和testShowPostsForUser_user_is_signed_in 。
如您所料,測試testShowPostsForUser_user_is_not_signed_in和testShowPostsForUser_user_is_signed_in用于測試用戶登錄和未登錄其Facebook帳戶的情況。
“標準” Mockito測試
@Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); instance = new FacebookPostsController(); ReflectionTestUtils.setField(instance, "socialContext", socialContext); }設(shè)置代碼相當簡單,包含三個簡單步驟:
testShowPostsForUser_user_is_not_signed_in方法將模擬的SocialContext配置為在調(diào)用其isSignedIn()方法時返回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()方法時返回true ,還有另外四行代碼可確保從模擬Facebook提要中返回posts列表并將其添加到模擬Model 。 調(diào)用showPostsForUser(...)之后,需要完成兩個附加步驟:驗證模擬Model包含posts列表,以及斷言showPostsForUser(...)的返回值為"show-posts" 。
接下來,Spring MVC Test框架代碼; 但是,在開始之前,您需要將以下依賴項添加到POM文件:
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${org.springframework-version}</version><scope>test</scope></dependency>Spring MVC測試
Spring MVC測試框架版本運行相同的兩個測試,但是方式不同……
@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)建一個FacebookPostsController的新實例,將模擬的SocialContext注入到該實例中。 但是,這一次, FacebookPostsController狀態(tài)已降級為局部變量,因為設(shè)置的重點是創(chuàng)建一個Spring的MockMvc實例,該實例用于執(zhí)行測試。 該mockMvc是通過調(diào)用創(chuàng)建MockMvcBuilders.standaloneSetup(instance).build()其中instance是FacebookPostsController對象,我們正在測試。
與Mockito版本類似, testShowPostsForUser_user_is_not_signed_in方法將模擬的SocialContext配置為在調(diào)用其isSignedIn()方法時返回false 。 這次,下一步是使用靜態(tài)方法創(chuàng)建一個稱為MockHttpServletRequestBuilder東西。
MockMvcRequestBuilders.get(...)和構(gòu)建器模式。 它被傳遞到mockMVC.perform(...)方法中,在此方法中,該方法用于創(chuàng)建MockHttpServletRequest對象,該對象用于定義測試的起點。 在此測試中,我要做的只是傳遞"/posts" URL并將輸入設(shè)置為“ any”媒體類型。 您可以使用諸如contentType() , contextPath() , cookie()等方法配置許多其他請求對象屬性。有關(guān)更多信息,請查看Spring Javadoc中的MockHttpServletRequest
mockMvc.perform()方法返回一個ResultActions對象。 這似乎是實際MvcResult的包裝。 ResultsActions是一個便捷對象,用于以與JUnit的assertEquals(...)或Mockito的verify(..)方法相同的方式聲明測試結(jié)果。 在這種情況下,我正在檢查結(jié)果Http狀態(tài)是否正常(即200),并且下一個視圖將"signin" 。
此測試與僅Mockito版本之間的區(qū)別在于,您不是直接測試對測試實例的方法調(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列表來準備測試的。 此方法的Spring Mvc Test部分與上述testShowPostsForUser_user_is_not_signed_in版本幾乎相同,不同之處在于,這次它使用andExpect(view().name("show-posts")檢查下一個視圖名稱"show-posts"而不是"sign-in" andExpect(view().name("show-posts")我在這里使用的代碼樣式與我在上面使用的樣式有些不同,并且是Spring的Guy偏愛的樣式。如果您能在Github上找到更多這種樣式的示例,持有Spring MVC Showcase應(yīng)用。
那么,您可以從此比較中得出什么結(jié)論? 公平地說,這不是真正的比較– Spring MVC Test API在建立標準Mockito技術(shù)的基礎(chǔ)上,采用了不同的方法,創(chuàng)建了一個框架,旨在僅在其本機運行時環(huán)境的模型中對Spring MVC控制器進行測試。 。
這對您是否有用,我會讓您決定。 它確實具有將控制器視為控制器而不是POJO的優(yōu)點,這意味著它們已經(jīng)過更徹底的測試。 從個人的角度來看,我喜歡加載Spring配置文件并將其用于集成測試的想法,這將在我的下一個博客中介紹。
- 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
總結(jié)
以上是生活随笔為你收集整理的Spring MVC测试框架入门–第1部分的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 部分小米手机被安装恶意软件!可篡改游览器
- 下一篇: 1-7 月全球电动汽车电池市场份额:宁德