javascript
spring不自动下载_Spring:自动接线或不自动接线
spring不自動下載
自從使用Spring 2.5以來,我從基于XML的應用程序上下文切換到了注釋。 盡管我發現那些非常有用且節省大量時間的人,但我始終覺得在靈活性方面我失去了一些東西。 特別是@Autowired批注-或標準@Inject-在我看來就像新的“新”,增加了我的類之間的聯系,使在需要時更難更改實現。 我仍然有這種感覺,但是我已經學到了一種有趣的模式來限制測試代碼時的問題,即當我想將bean的真實實現替換為模擬時。 讓我們用一個例子來說明。 我想構建一個應用程序,以便為我在網絡上找到有趣的東西。 我將從一個接受URL的服務開始,如果它是一個有趣的新服務,則將其添加書簽。 直到最近,我可能已經編寫了如下代碼:
@Named public class AwesomenessFinder {@Injectprivate BlogAnalyzer blogAnalyzer;@Injectprivate BookmarkService bookmarkService;public void checkBlog(String url) {if (!bookmarkService.contains(url) && blogAnalyzer.isInteresting(url)) {bookmarkService.bookmark(url);}} }不好,你明白為什么嗎? 如果沒有,請繼續閱讀,希望您今天能學到一些有用的東西。 因為我很認真,所以我想為此代碼創建單元測試。 希望我的算法很好,但是我想確保它不會為無聊的博客添加書簽或為相同的URL添加兩次書簽。 那就是問題所在,我想將AwesomenessFinder與它的依賴隔離開來。 如果我使用的是XML配置,則可以在測試上下文中簡單地注入模擬實現,是否可以使用批注來實現? 嗯,是! 有一種方法,帶有@Primary批注。 讓我們嘗試為BlogAnalyzer和BookmarkService創建模擬實現。
@Named @Primary public class BlogAnalyzerMock implements BlogAnalyzer {public boolean isInteresting(String url) {return true;} }@Named @Primary public class BookmarkServiceMock implements BookmarkService {Set bookmarks = new HashSet();public boolean contains(String url) {return bookmarks.contains(url);}public void bookmark(String url) {bookmarks.add(url);} }因為我使用Maven并將這些模擬放置在test / java目錄中,所以主應用程序將看不到它們,并將注入實際的實現。 另一方面,單元測試將看到2種實現。 @Primary是必需的,以防止出現類似以下的異常:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [service.BlogAnalyzer] is defined: expected single matching bean but found 2: [blogAnalyzerMock, blogAnalyzerImpl]現在,我可以測試我的算法了:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:application-context.xml") public class AwesomenessFinderTest {@Injectprivate AwesomenessFinder awesomenessFinder;@Injectprivate BookmarkService bookmarkService;@Testpublic void checkInterestingBlog_bookmarked() {String url = "http://www.javaspecialists.eu";assertFalse(bookmarkService.contains(url));awesomenessFinder.checkBlog(url);assertTrue(bookmarkService.contains(url));} }不錯,我測試了幸福的道路,一個有趣的博客被加了書簽。 現在我該如何測試其他情況。 當然,我可以在模擬中添加一些邏輯,以查找某些已經添加了書簽或不感興趣的URL,但這會變得笨拙。 這是一個非常簡單的算法,想象一下測試更復雜的東西有多糟糕。 有一種更好的方法需要重新設計我的類以及注入依賴項的方法。 方法如下:
@Named public class AwesomenessFinder {private BlogAnalyzer blogAnalyzer;private BookmarkService bookmarkService;@Injectpublic AwesomenessFinder(BlogAnalyzer blogAnalyzer, BookmarkService bookmarkService) {this.blogAnalyzer = blogAnalyzer;this.bookmarkService = bookmarkService;}public void checkBlog(String url) {if (!bookmarkService.contains(url) && blogAnalyzer.isInteresting(url)) {bookmarkService.bookmark(url);}} }請注意,我仍然使用@Inject注釋自動關聯我的依賴項,因此AwesomenessFinder的調用者不會受到影響。 例如,客戶端類中的以下內容仍然有效:
@Inject private AwesomenessFinder awesomenessFinder;但是,最大的不同是我在構造函數級別自動裝配,這為我提供了一種注入模擬實現的干凈方法。 而且,由于我們是在模擬,所以我們使用一個模擬庫。 去年,我寫了一篇有關嘲諷的文章,其中我使用了丑陋的二傳手來注入嘲諷。 有了這里提到的技術,我不再需要暴露依賴項,我得到了更好的封裝。 這是更新后的測試用例的樣子:
public class AwesomenessFinderTest {@Testpublic void checkInterestingBlog_bookmarked() {BookmarkService bookmarkService = mock(BookmarkService.class);when(bookmarkService.contains(anyString())).thenReturn(false);BlogAnalyzer blogAnalyzer = mock(BlogAnalyzer.class);when(blogAnalyzer.isInteresting(anyString())).thenReturn(true);AwesomenessFinder awesomenessFinder = new AwesomenessFinder(blogAnalyzer, bookmarkService);String url = "http://www.javaspecialists.eu";awesomenessFinder.checkBlog(url);verify(bookmarkService).bookmark(url);} }請注意,現在這是純Java語言,無需使用Spring注入模擬。 而且,這些模擬的定義與它們的用法位于同一位置,從而簡化了維護。 為了更進一步,讓我們實現其他測試用例。 為了避免代碼重復,我們將重構測試類并引入一些枚舉,以使測試用例盡可能地具有表達力。
public class AwesomenessFinderTest {private enum Knowledge {KNOWN, UNKNOWN};private enum Quality {INTERESTING, BORING};private enum ExpectedBookmark {STORED, IGNORED}private enum ExpectedAnalysis {ANALYZED, SKIPPED}@Testpublic void checkInterestingBlog_bookmarked() {checkCase(Knowledge.UNKNOWN, Quality.INTERESTING,ExpectedBookmark.STORED, ExpectedAnalysis.ANALYZED);}@Testpublic void checkBoringBlog_ignored() {checkCase(Knowledge.UNKNOWN, Quality.BORING,ExpectedBookmark.IGNORED, ExpectedAnalysis.ANALYZED);}@Testpublic void checkKnownBlog_ignored() {checkCase(Knowledge.KNOWN, Quality.INTERESTING,ExpectedBookmark.IGNORED, ExpectedAnalysis.SKIPPED);}private void checkCase(Knowledge knowledge, Quality quality,ExpectedBookmark expectedBookmark, ExpectedAnalysis expectedAnalysis) {BookmarkService bookmarkService = mock(BookmarkService.class);boolean alreadyBookmarked = (knowledge == Knowledge.KNOWN) ? true : false;when(bookmarkService.contains(anyString())).thenReturn(alreadyBookmarked);BlogAnalyzer blogAnalyzer = mock(BlogAnalyzer.class);boolean interesting = (quality == Quality.INTERESTING) ? true : false;when(blogAnalyzer.isInteresting(anyString())).thenReturn(interesting);AwesomenessFinder awesomenessFinder = new AwesomenessFinder(blogAnalyzer, bookmarkService);String url = "whatever";awesomenessFinder.checkBlog(url);if (expectedBookmark == ExpectedBookmark.STORED) {verify(bookmarkService).bookmark(url);} else {verify(bookmarkService, never()).bookmark(url);}if (expectedAnalysis == ExpectedAnalysis.ANALYZED) {verify(blogAnalyzer).isInteresting(url);} else {verify(blogAnalyzer, never()).isInteresting(url);}} } 最后但并非最不重要的一點是,構造函數注入的一個不錯的好處是能夠將類的所有依賴項放在同一位置(構造函數)。 如果依賴項列表超出了控制范圍,則構造函數的大小會產生非常明顯的代碼味道。 這表明您在班級中肯定承擔了多個責任,您應該將其劃分為多個班級,以便于單元測試更容易地隔離。
翻譯自: https://www.javacodegeeks.com/2013/04/spring-to-autowire-or-not-to-autowire.html
spring不自動下載
總結
以上是生活随笔為你收集整理的spring不自动下载_Spring:自动接线或不自动接线的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Cloud教程– Spri
- 下一篇: Spring MVC中@RequestP