日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

如何模拟Spring bean(版本2)

發布時間:2023/12/3 javascript 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何模拟Spring bean(版本2) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

大約一年前,我寫了一篇博客文章如何模擬Spring Bean 。 所描述的模式對生產代碼幾乎沒有侵入性。 正如讀者Colin在評論中正確指出的那樣,基于@Profile注釋的間諜/模擬Spring bean是更好的選擇。 這篇博客文章將描述這種技術。 我在工作中以及副項目中都成功使用了這種方法。

請注意,在您的應用程序中普遍出現的嘲笑通常被視為設計氣味。

介紹生產代碼

首先,我們需要測試代碼以演示模擬。 我們將使用以下簡單的類:

@Repository public class AddressDao {public String readAddress(String userName) {return "3 Dark Corner";} }@Service public class AddressService {private AddressDao addressDao;@Autowiredpublic AddressService(AddressDao addressDao) {this.addressDao = addressDao;}public String getAddressForUser(String userName){return addressDao.readAddress(userName);} }@Service public class UserService {private AddressService addressService;@Autowiredpublic UserService(AddressService addressService) {this.addressService = addressService;}public String getUserDetails(String userName){String address = addressService.getAddressForUser(userName);return String.format("User %s, %s", userName, address);} }

當然,這段代碼沒有多大意義,但對于演示如何模擬Spring bean來說將是一個很好的選擇。 AddressDao只是返回字符串,因此模擬了從某些數據源的讀取。 它自動連接到AddressService 。 該bean被自動連接到UserService ,后者用于構造帶有用戶名和地址的字符串。

請注意,我們將構造函數注入用作字段注入被認為是不好的做法。 如果要為應用程序強制執行構造函數注入,Oliver Gierke(Spring生態系統開發人員和Spring Data負責人)最近創建了一個非常不錯的項目Ninjector 。

掃描所有這些bean的配置是相當標準的Spring Boot主類:

@SpringBootApplication public class SimpleApplication {public static void main(String[] args) {SpringApplication.run(SimpleApplication.class, args);} }

模擬Spring Bean(無AOP)

讓我們在模擬AddressDao地方測試AddressService類。 我們可以創建通過Spring”這個模擬@Profiles@Primary注釋是這樣的:

@Profile("AddressService-test") @Configuration public class AddressDaoTestConfiguration {@Bean@Primarypublic AddressDao addressDao() {return Mockito.mock(AddressDao.class);} }

僅當Spring概要文件AddressService-test處于活動狀態時,才會應用此測試配置。 應用時,它將注冊AddressDao類型的bean,該類型是Mockito創建的模擬實例。 @Primary注釋告訴Spring在有人自動裝配AddressDao bean時使用此實例,而不是實際實例。

測試類使用的是JUnit框架:

@ActiveProfiles("AddressService-test") @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(SimpleApplication.class) public class AddressServiceITest {@Autowired private AddressService addressService;@Autowiredprivate AddressDao addressDao;@Testpublic void testGetAddressForUser() {// GIVENMockito.when(addressDao.readAddress("john")).thenReturn("5 Bright Corner");// WHEN String actualAddress = addressService.getAddressForUser("john");// THEN Assert.assertEquals("5 Bright Corner", actualAddress);} }

我們激活配置文件AddressService-test以啟用AddressDao AddressService-test 。 Spring集成測試需要使用@RunWith注釋,而@SpringApplicationConfiguration定義將使用哪種Spring配置來構造測試環境。 在測試之前,我們自動連接被測試的AddressService實例和AddressDao模擬。

如果您使用的是Mockito,則隨后的測試方法應明確。 在GIVEN階段,我們將所需的行為記錄到模擬實例中。 在WHEN階段,我們執行測試代碼,在THEN階段,我們驗證測試代碼是否返回了我們期望的值。

監視Spring Bean(無AOP)

對于間諜示例,將在AddressService實例上進行間諜:

@Profile("UserService-test") @Configuration public class AddressServiceTestConfiguration {@Bean@Primarypublic AddressService addressServiceSpy(AddressService addressService) {return Mockito.spy(addressService);} }

僅當配置文件UserService-test處于活動狀態時,才會對此組件配置進行Spring掃描。 它定義了AddressService類型的主bean。 @Primary告訴Spring使用該實例,以防在Spring上下文中存在兩個這種類型的bean。 在構造此bean的過程中,我們從Spring上下文自動裝配了AddressService現有實例,并使用Mockito的間諜功能。 我們正在注冊的bean有效地將所有調用委托給原始實例,但是Mockito間諜程序使我們可以驗證所偵查實例的交互。

我們將以這種方式測試UserService行為:

@ActiveProfiles("UserService-test") @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(SimpleApplication.class) public class UserServiceITest {@Autowiredprivate UserService userService;@Autowiredprivate AddressService addressService;@Testpublic void testGetUserDetails() {// GIVEN - Spring scanned by SimpleApplication class// WHENString actualUserDetails = userService.getUserDetails("john");// THENAssert.assertEquals("User john, 3 Dark Corner", actualUserDetails);Mockito.verify(addressService).getAddressForUser("john");} }

為了進行測試,我們激活了UserService-test配置文件,因此將應用我們的間諜配置。 我們自動裝配UserService這是在測試和AddressService ,目前正在通過窺探的Mockito。

我們不需要為在GIVEN階段進行測試準備任何行為。 W HEN相被測明顯執行代碼。 在THEN階段,我們驗證測試代碼是否返回了我們期望的值,以及是否使用正確的參數執行了addressService調用。

Mockito和Spring AOP的問題

假設現在我們要使用Spring AOP模塊來處理一些跨領域的問題。 例如,以這種方式記錄對Spring Bean的調用:

package net.lkrnac.blog.testing.mockbeanv2.aoptesting;import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component;import lombok.extern.slf4j.Slf4j;@Aspect @Component @Slf4j @Profile("aop") //only for example purposes public class AddressLogger {@Before("execution(* net.lkrnac.blog.testing.mockbeanv2.beans.*.*(..))")public void logAddressCall(JoinPoint jp){log.info("Executing method {}", jp.getSignature());} }

在從包net.lkrnac.blog.testing.mockbeanv2調用Spring bean之前,將應用此AOP方面。 它使用Lombok的注釋@Slf4j記錄調用方法的簽名。 注意,僅當定義了aop概要文件時才創建此bean。 我們正在使用此配置文件將AOP和非AOP測試示例分開。 在實際的應用程序中,您不想使用此類配置文件。

我們還需要為我們的應用程序啟用AspectJ,因此以下所有示例都將使用此Spring Boot主類:

@SpringBootApplication @EnableAspectJAutoProxy public class AopApplication {public static void main(String[] args) {SpringApplication.run(AopApplication.class, args);} }

AOP構造由@EnableAspectJAutoProxy啟用。

但是,如果我們將Mockito與Spring AOP結合進行模擬,則此類AOP構造可能會出現問題。 這是因為兩者都使用CGLIB代理真實實例,并且當Mockito代理包裝到Spring代理中時,我們會遇到類型不匹配的問題。 這些可以通過使用ScopedProxyMode.TARGET_CLASS配置bean的作用域來ScopedProxyMode.TARGET_CLASS ,但是Mockito的verify ()調用仍然會因NotAMockException失敗。 如果我們為UserServiceITest啟用aop配置文件,則可以看到此類問題。

由Spring AOP代理的模擬Spring Bean

為了克服這些問題,我們將模擬包裝到這個Spring bean中:

package net.lkrnac.blog.testing.mockbeanv2.aoptesting;import org.mockito.Mockito; import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Repository;import lombok.Getter; import net.lkrnac.blog.testing.mockbeanv2.beans.AddressDao;@Primary @Repository @Profile("AddressService-aop-mock-test") public class AddressDaoMock extends AddressDao{@Getterprivate AddressDao mockDelegate = Mockito.mock(AddressDao.class);public String readAddress(String userName) {return mockDelegate.readAddress(userName);} }

@Primary注釋可確保在注入過程中,此bean優先于實際的AddressDao bean。 為了確保僅將其應用于特定測試,我們為此bean定義了配置文件AddressService-aop-mock-test 。 它繼承了AddressDao類,因此可以完全替代該類型。

為了偽造行為,我們定義了AddressDao類型的模擬實例,該實例通過由Lombok的@Getter批注定義的getter @Getter 。 我們還實現了readAddress()方法,該方法有望在測試期間被調用。 此方法僅將調用委派給模擬實例。

使用該模擬程序的測試如下所示:

@ActiveProfiles({"AddressService-aop-mock-test", "aop"}) @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(AopApplication.class) public class AddressServiceAopMockITest {@Autowiredprivate AddressService addressService; @Autowiredprivate AddressDao addressDao;@Testpublic void testGetAddressForUser() {// GIVENAddressDaoMock addressDaoMock = (AddressDaoMock) addressDao;Mockito.when(addressDaoMock.getMockDelegate().readAddress("john")).thenReturn("5 Bright Corner");// WHEN String actualAddress = addressService.getAddressForUser("john");// THEN ?Assert.assertEquals("5 Bright Corner", actualAddress);} }

在測試中,我們定義AddressService-aop-mock-test配置文件以激活AddressDaoMock并定義aop配置文件以激活AddressLogger AOP方面。 為了進行測試,我們自動裝配了bean addressService及其偽造的依賴項addressDao 。 我們知道, addressDao將是AddressDaoMock類型的,因為此bean被標記為@Primary 。 因此,我們可以將其mockDelegate轉換mockDelegate行為記錄到mockDelegate 。

當我們調用測試方法時,應使用記錄的行為,因為我們希望測試方法使用AddressDao依賴項。

監視Spring AOP代理的Spring bean

類似的模式可用于監視實際實現。 這就是我們的間諜的樣子:

package net.lkrnac.blog.testing.mockbeanv2.aoptesting;import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service;import lombok.Getter; import net.lkrnac.blog.testing.mockbeanv2.beans.AddressDao; import net.lkrnac.blog.testing.mockbeanv2.beans.AddressService;@Primary @Service @Profile("UserService-aop-test") public class AddressServiceSpy extends AddressService{@Getterprivate AddressService spyDelegate;@Autowiredpublic AddressServiceSpy(AddressDao addressDao) {super(null);spyDelegate = Mockito.spy(new AddressService(addressDao));}public String getAddressForUser(String userName){return spyDelegate.getAddressForUser(userName);} }

如我們所見,該間諜與AddressDaoMock非常相似。 但是在這種情況下,真正的bean使用構造函數注入來自動裝配其依賴關系。 因此,我們需要定義非默認構造函數,并且還要進行構造函數注入。 但是我們不會將注入的依賴項傳遞給父構造函數。

為了啟用對真實對象的監視,我們將構造具有所有依賴項的新實例,將其包裝到Mockito間諜實例中,并將其存儲到spyDelegate屬性中。 我們期望在測試期間調用方法getAddressForUser() ,因此我們將此調用委托給spyDelegate 。 可以在測試中通過由Lombok的@Getter批注定義的getter訪問此屬性。

測試本身如下所示:

@ActiveProfiles({"UserService-aop-test", "aop"}) @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(AopApplication.class) public class UserServiceAopITest {@Autowiredprivate UserService userService;@Autowiredprivate AddressService addressService;@Testpublic void testGetUserDetails() {// GIVENAddressServiceSpy addressServiceSpy = (AddressServiceSpy) addressService;// WHENString actualUserDetails = userService.getUserDetails("john");// THEN Assert.assertEquals("User john, 3 Dark Corner", actualUserDetails);Mockito.verify(addressServiceSpy.getSpyDelegate()).getAddressForUser("john");} }

這是非常簡單的。 配置文件UserService-aop-test確保可以掃描AddressServiceSpy 。 配置文件aopAddressLogger方面確保相同。 當我們自動測試對象UserService及其依賴項AddressService ,我們知道可以將其spyDelegateAddressServiceSpy并在調用測試方法后驗證其spyDelegate屬性的調用。

由Spring AOP代理的假Spring Bean

顯然,將調用委派給Mockito模擬或間諜會使測試復雜化。 如果我們僅需要偽造邏輯,那么這些模式通常會被大刀闊斧。 在這種情況下,我們可以使用這些偽造品:

@Primary @Repository @Profile("AddressService-aop-fake-test") public class AddressDaoFake extends AddressDao{public String readAddress(String userName) {return userName + "'s address";} }

并將其用于這種方式的測試:

@ActiveProfiles({"AddressService-aop-fake-test", "aop"}) @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(AopApplication.class) public class AddressServiceAopFakeITest {@Autowiredprivate AddressService addressService; @Testpublic void testGetAddressForUser() {// GIVEN - Spring context// WHEN String actualAddress = addressService.getAddressForUser("john");// THEN ?Assert.assertEquals("john's address", actualAddress);} }

我認為這個測試不需要解釋。

  • 這些示例的源代碼托管在Github上。

翻譯自: https://www.javacodegeeks.com/2016/01/mock-spring-bean-version-2.html

總結

以上是生活随笔為你收集整理的如何模拟Spring bean(版本2)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。