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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

spring-bean版本_如何模拟Spring bean(版本2)

發(fā)布時(shí)間:2023/12/3 javascript 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring-bean版本_如何模拟Spring bean(版本2) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

spring-bean版本

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

請(qǐng)注意,在您的應(yīng)用程序中普遍出現(xiàn)的嘲笑通常被視為設(shè)計(jì)氣味。

介紹生產(chǎn)代碼

首先,我們需要測(cè)試代碼以演示模擬。 我們將使用以下簡(jiǎn)單的類:

@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);} }

當(dāng)然,這段代碼沒(méi)有多大意義,但對(duì)于演示如何模擬Spring bean來(lái)說(shuō)將是一個(gè)很好的選擇。 AddressDao只是返回字符串,因此模擬了從某些數(shù)據(jù)源的讀取。 它自動(dòng)連接到AddressService 。 該bean被自動(dòng)連接到UserService ,后者用于構(gòu)造具有用戶名和地址的字符串。

請(qǐng)注意,我們將構(gòu)造函數(shù)注入用作字段注入被認(rèn)為是不好的做法。 如果要為應(yīng)用程序強(qiáng)制執(zhí)行構(gòu)造函數(shù)注入,Oliver Gierke(Spring生態(tài)系統(tǒng)開(kāi)發(fā)人員和Spring Data負(fù)責(zé)人)最近創(chuàng)建了一個(gè)非常不錯(cuò)的項(xiàng)目Ninjector 。

掃描所有這些bean的配置是相當(dāng)標(biāo)準(zhǔn)的Spring Boot主類:

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

模擬Spring Bean(無(wú)AOP)

讓我們?cè)谀MAddressDao地方測(cè)試AddressService類。 我們可以通過(guò)Spring的@Profiles@Primary批注創(chuàng)建這種模擬:

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

僅當(dāng)Spring概要文件AddressService-test處于活動(dòng)狀態(tài)時(shí),才會(huì)應(yīng)用此測(cè)試配置。 應(yīng)用時(shí),它將注冊(cè)AddressDao類型的bean,該類型是Mockito創(chuàng)建的模擬實(shí)例。 @Primary注釋告訴Spring在有人自動(dòng)裝配AddressDao bean時(shí)使用此實(shí)例,而不是實(shí)際實(shí)例。

測(cè)試類使用的是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集成測(cè)試需要使用@RunWith注釋,而@SpringApplicationConfiguration定義將使用哪個(gè)Spring配置來(lái)構(gòu)建測(cè)試環(huán)境。 在測(cè)試之前,我們會(huì)自動(dòng)連接被測(cè)試的AddressService實(shí)例和AddressDao模擬。

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

監(jiān)視Spring Bean(無(wú)AOP)

對(duì)于間諜示例,將在AddressService實(shí)例上進(jìn)行間諜:

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

僅當(dāng)配置文件UserService-test處于活動(dòng)狀態(tài)時(shí),才會(huì)對(duì)此組件配置進(jìn)行Spring掃描。 它定義了AddressService類型的主bean。 @Primary告訴Spring使用這個(gè)實(shí)例,以防在Spring上下文中存在兩個(gè)這種類型的bean。 在構(gòu)造此bean的過(guò)程中,我們從Spring上下文自動(dòng)裝配了AddressService現(xiàn)有實(shí)例,并使用Mockito的間諜功能。 我們正在注冊(cè)的bean有效地將所有調(diào)用委派給了原始實(shí)例,但是Mockito間諜程序使我們能夠驗(yàn)證所監(jiān)視實(shí)例上的交互。

我們將以這種方式測(cè)試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");} }

為了進(jìn)行測(cè)試,我們激活了UserService-test配置文件,因此將應(yīng)用我們的間諜配置。 我們自動(dòng)裝配UserService這是在測(cè)試和AddressService ,目前正在通過(guò)窺探的Mockito。

我們不需要為在GIVEN階段進(jìn)行測(cè)試準(zhǔn)備任何行為。 W HEN相被測(cè)明顯執(zhí)行代碼。 在THEN階段,我們驗(yàn)證測(cè)試代碼是否返回了期望的值,以及是否使用正確的參數(shù)執(zhí)行了addressService調(diào)用。

Mockito和Spring AOP的問(wèn)題

假設(shè)現(xiàn)在我們要使用Spring AOP模塊來(lái)處理一些跨領(lǐng)域的問(wèn)題。 例如,以這種方式記錄對(duì)Spring Bean的調(diào)用:

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調(diào)用Spring bean之前,將應(yīng)用此AOP方面。 它使用Lombok的注釋@Slf4j記錄調(diào)用方法的簽名。 注意,僅當(dāng)定義了aop概要文件時(shí)才創(chuàng)建此bean。 我們正在使用此配置文件將AOP和非AOP測(cè)試示例分開(kāi)。 在實(shí)際的應(yīng)用程序中,您不想使用此類配置文件。

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

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

AOP構(gòu)造由@EnableAspectJAutoProxy啟用。

但是,如果我們將Mockito與Spring AOP結(jié)合進(jìn)行模擬,則此類AOP構(gòu)造可能會(huì)出現(xiàn)問(wèn)題。 這是因?yàn)閮烧叨际褂肅GLIB代理真實(shí)實(shí)例,并且當(dāng)Mockito代理包裝到Spring代理中時(shí),我們會(huì)遇到類型不匹配的問(wèn)題。 這些可以通過(guò)使用ScopedProxyMode.TARGET_CLASS配置bean的作用域來(lái)ScopedProxyMode.TARGET_CLASS ,但是Mockito的verify ()調(diào)用仍然會(huì)因NotAMockException失敗。 如果我們?yōu)?strong>UserServiceITest啟用aop配置文件,則可以看到此類問(wèn)題。

由Spring AOP代理的模擬Spring Bean

為了克服這些問(wèn)題,我們將模擬包裝到這個(gè)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注釋可確保在注入過(guò)程中,此bean優(yōu)先于實(shí)際的AddressDao bean。 為了確保僅將其應(yīng)用于特定測(cè)試,我們?yōu)榇薭ean定義了配置文件AddressService-aop-mock-test 。 它繼承了AddressDao類,因此可以完全替代該類型。

為了偽造行為,我們定義了AddressDao類型的模擬實(shí)例,該實(shí)例通過(guò)Lombok的@Getter注釋定義的getter @Getter 。 我們還實(shí)現(xiàn)了readAddress()方法,該方法有望在測(cè)試期間被調(diào)用。 此方法只是將調(diào)用委派給模擬實(shí)例。

使用該模擬程序的測(cè)試如下所示:

@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);} }

在測(cè)試中,我們定義AddressService-aop-mock-test配置文件以激活AddressDaoMock并定義aop配置文件以激活AddressLogger AOP方面。 為了進(jìn)行測(cè)試,我們自動(dòng)測(cè)試bean的addressService及其偽造的依賴項(xiàng)addressDao 。 我們知道, addressDao將是AddressDaoMock類型的,因?yàn)榇薭ean被標(biāo)記為@Primary 。 因此,我們可以將其mockDelegate轉(zhuǎn)換mockDelegate行為記錄到mockDelegate

當(dāng)我們調(diào)用測(cè)試方法時(shí),應(yīng)使用記錄的行為,因?yàn)槲覀兿M麥y(cè)試方法使用AddressDao依賴項(xiàng)。

監(jiān)視Spring AOP代理的Spring bean

類似的模式可用于監(jiān)視實(shí)際實(shí)現(xiàn)。 這就是我們的間諜的樣子:

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);} }

如我們所見(jiàn),該間諜與AddressDaoMock非常相似。 但是在這種情況下,真正的bean使用構(gòu)造函數(shù)注入自動(dòng)關(guān)聯(lián)其依賴項(xiàng)。 因此,我們需要定義非默認(rèn)構(gòu)造函數(shù),并且還要進(jìn)行構(gòu)造函數(shù)注入。 但是,我們不會(huì)將注入的依賴項(xiàng)傳遞給父構(gòu)造函數(shù)。

為了啟用對(duì)真實(shí)對(duì)象的監(jiān)視,我們將構(gòu)造具有所有依賴項(xiàng)的新實(shí)例,將其包裝到Mockito間諜實(shí)例中,并將其存儲(chǔ)到spyDelegate屬性中。 我們期望在測(cè)試期間調(diào)用方法getAddressForUser() ,因此我們將此調(diào)用委托給spyDelegate 。 可以在測(cè)試中通過(guò)Lombok的@Getter批注定義的getter訪問(wèn)此屬性。

測(cè)試本身如下所示:

@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");} }

這是非常簡(jiǎn)單的。 配置文件UserService-aop-test確保可以掃描AddressServiceSpy 。 配置文件aopAddressLogger方面確保相同。 在自動(dòng)裝配測(cè)試對(duì)象UserService及其依賴項(xiàng)AddressService ,我們知道可以將其spyDelegateAddressServiceSpy并在調(diào)用測(cè)試方法后驗(yàn)證其spyDelegate屬性的調(diào)用。

由Spring AOP代理的假Spring Bean

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

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

并以這種方式用于測(cè)試:

@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);} }

我認(rèn)為這個(gè)測(cè)試不需要解釋。

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

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

spring-bean版本

總結(jié)

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

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。