javascript
spring不自动下载_Spring:自动接线或不自动接线
spring不自動(dòng)下載
自從使用Spring 2.5以來,我從基于XML的應(yīng)用程序上下文切換到了注釋。 盡管我發(fā)現(xiàn)那些非常有用且節(jié)省大量時(shí)間的人,但我始終覺得在靈活性方面我失去了一些東西。 特別是@Autowired批注-或標(biāo)準(zhǔn)@Inject-在我看來就像新的“新”,增加了我的類之間的聯(lián)系,使在需要時(shí)更難更改實(shí)現(xiàn)。 我仍然有這種感覺,但是我已經(jīng)學(xué)到了一種有趣的模式來限制測試代碼時(shí)的問題,即當(dāng)我想將bean的真實(shí)實(shí)現(xiàn)替換為模擬時(shí)。 讓我們用一個(gè)例子來說明。 我想構(gòu)建一個(gè)應(yīng)用程序,以便為我在網(wǎng)絡(luò)上找到有趣的東西。 我將從一個(gè)接受URL的服務(wù)開始,如果它是一個(gè)有趣的新服務(wù),則將其添加書簽。 直到最近,我可能已經(jīng)編寫了如下代碼:
@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);}} }不好,你明白為什么嗎? 如果沒有,請繼續(xù)閱讀,希望您今天能學(xué)到一些有用的東西。 因?yàn)槲液苷J(rèn)真,所以我想為此代碼創(chuàng)建單元測試。 希望我的算法很好,但是我想確保它不會(huì)為無聊的博客添加書簽或?yàn)橄嗤腢RL添加兩次書簽。 那就是問題所在,我想將AwesomenessFinder與它的依賴隔離開來。 如果我使用的是XML配置,則可以在測試上下文中簡單地注入模擬實(shí)現(xiàn),是否可以使用批注來實(shí)現(xiàn)? 嗯,是! 有一種方法,帶有@Primary批注。 讓我們嘗試為BlogAnalyzer和BookmarkService創(chuàng)建模擬實(shí)現(xiàn)。
@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);} }因?yàn)槲沂褂肕aven并將這些模擬放置在test / java目錄中,所以主應(yīng)用程序?qū)⒖床坏剿鼈?#xff0c;并將注入實(shí)際的實(shí)現(xiàn)。 另一方面,單元測試將看到2種實(shí)現(xiàn)。 @Primary是必需的,以防止出現(xiàn)類似以下的異常:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [service.BlogAnalyzer] is defined: expected single matching bean but found 2: [blogAnalyzerMock, blogAnalyzerImpl]現(xiàn)在,我可以測試我的算法了:
@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));} }不錯(cuò),我測試了幸福的道路,一個(gè)有趣的博客被加了書簽。 現(xiàn)在我該如何測試其他情況。 當(dāng)然,我可以在模擬中添加一些邏輯,以查找某些已經(jīng)添加了書簽或不感興趣的URL,但這會(huì)變得笨拙。 這是一個(gè)非常簡單的算法,想象一下測試更復(fù)雜的東西有多糟糕。 有一種更好的方法需要重新設(shè)計(jì)我的類以及注入依賴項(xiàng)的方法。 方法如下:
@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注釋自動(dòng)關(guān)聯(lián)我的依賴項(xiàng),因此AwesomenessFinder的調(diào)用者不會(huì)受到影響。 例如,客戶端類中的以下內(nèi)容仍然有效:
@Inject private AwesomenessFinder awesomenessFinder;但是,最大的不同是我在構(gòu)造函數(shù)級別自動(dòng)裝配,這為我提供了一種注入模擬實(shí)現(xiàn)的干凈方法。 而且,由于我們是在模擬,所以我們使用一個(gè)模擬庫。 去年,我寫了一篇有關(guān)嘲諷的文章,其中我使用了丑陋的二傳手來注入嘲諷。 有了這里提到的技術(shù),我不再需要暴露依賴項(xiàng),我得到了更好的封裝。 這是更新后的測試用例的樣子:
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);} }請注意,現(xiàn)在這是純Java語言,無需使用Spring注入模擬。 而且,這些模擬的定義與它們的用法位于同一位置,從而簡化了維護(hù)。 為了更進(jìn)一步,讓我們實(shí)現(xiàn)其他測試用例。 為了避免代碼重復(fù),我們將重構(gòu)測試類并引入一些枚舉,以使測試用例盡可能地具有表達(dá)力。
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);}} } 最后但并非最不重要的一點(diǎn)是,構(gòu)造函數(shù)注入的一個(gè)不錯(cuò)的好處是能夠?qū)㈩惖乃幸蕾図?xiàng)放在同一位置(構(gòu)造函數(shù))。 如果依賴項(xiàng)列表超出了控制范圍,則構(gòu)造函數(shù)的大小會(huì)產(chǎn)生非常明顯的代碼味道。 這表明您在班級中肯定承擔(dān)了多個(gè)責(zé)任,您應(yīng)該將其劃分為多個(gè)班級,以便于單元測試更容易地隔離。
翻譯自: https://www.javacodegeeks.com/2013/04/spring-to-autowire-or-not-to-autowire.html
spring不自動(dòng)下載
總結(jié)
以上是生活随笔為你收集整理的spring不自动下载_Spring:自动接线或不自动接线的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Cloud教程– Spri
- 下一篇: 苹果手机忘记密码打不开手机怎么办