当前位置: 首页 > wzjs >正文

烟台网站优化推广在线作图软件

烟台网站优化推广,在线作图软件,百度seo排名优化软件化,2023免费推广入口问题描述 在使用MockBean 和 SpyBean 注解的时候,需要注意:MockBean 会完全 mock 掉这个 bean,也就是说,假如你指定了 在调用方法 A 时按 mock 期望返回,而没有指定调用方法 B 时返回什么,那么你在调用方法…

问题描述

在使用@MockBean 和 @SpyBean 注解的时候,需要注意:@MockBean 会完全 mock 掉这个 bean,也就是说,假如你指定了 在调用方法 A 时按 mock 期望返回,而没有指定调用方法 B 时返回什么,那么你在调用方法 B 时,方法 B 会直接返回 Null,换句话说,当你使用 @MockBean 的时候,那个 bean 除了按你给出的 case 返回之外,其余情况都返回 null。而@SpyBean 不一样,@SpyBean 支持“非预设时进行真实调用”,即假如你指定了 在调用方法 A 时按 mock 期望返回,而没有指定调用方法 B 时返回什么,那么你在调用方法 B 时,方法 B 会进行真实的调用,这是 @SpyBean 比 @MockBean 要丰富的功能。但是,@SpyBean 只能用在真实的 bean 身上,而用在接口上时,则会直接报错,错误内容是接口不能够被实例化。因此在对外部接口进行 mock 时,往往只能使用@MockBean。

但是,@MockBean 在用在接口上时,有时会出现一种 case 是:@MockBean mock 的 bean 并不能在长链路调用时一直生效。比如,现有的调用链路是 A->B->C->D,D 是外部接口,现在我使用 @MockBean 标记 D,期望 D 按照我 mock 的行为来返回,但是会出现一个问题:在单测中,我的入口是 A,结果走到 D 时仍旧会发起真实调用,而如果你再写一个单测,直接测调用 D 时的表现,却发现 D 的表现符合当初的 mock 预期,这是为什么呢?

举例说明:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = BgMoriaApplication.class)
@ActiveProfiles("test")
@WebAppConfiguration
@Slf4j
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {TigerConcurrentConsumer.class, TigerMessageProducer.class}
))
public abstract class BaseApiTest {@MockBeanprivate RegulatedUserAddressSnapshotQueryForSPService mockServicepublic void mockRegulatedQueryAddressEmptyResponse() {Mockito.when(mockService.queryAddressInfoForPaymentScene(any())).thenReturn(buildEmptyBaseResponse(QueryAddressSnapshotResponse.class));}
}

在上面的单测基础类中,我定义了要 mock 的接口为mockService.queryAddressInfoForPaymentScene,并期望他返回一个空对象。

而我实际的调用链路为:

  1.addressSnapshotService.queryHolderNameAddress   ->2.raphaelIntegration.queryAddressSnapshot  ->3. regulatedUserAddressSnapshotQueryForSPService.queryAddressInfoForPaymentScene

我的单测为:

@Slf4j
public class SorosRiskSpiTest extends BaseApiTest{@Testpublic void testQueryRegulatedHolderNameAddressAndMobileWithEmptyResponse_NonRegulatedNotNullResponse() {mockRegulatedQueryAddressEmptyResponse();mockRegulatedQueryAddressMobileEmptyResponse();Long uid = 27953383161566L;String addressSnapshotId = "228100002134397257";String regionId = "128";UserAddressSnapshotVO addressSnapshotVO = addressSnapshotService.queryHolderNameAddress(uid, addressSnapshotId, regionId);Assert.notNull(addressSnapshotVO);AddressSnapshotMobileVO userAddressSnapshotMobileVO = addressSnapshotService.queryAddressSnapshotMobile(uid, addressSnapshotId, regionId);Assert.notNull(userAddressSnapshotMobileVO);}
}

运行单测会发现,还是真实地调用了regulatedUserAddressSnapshotQueryForSPService.queryAddressInfoForPaymentScene

可能的一个原因是Bean 依赖注入的顺序 和 Spring 上下文刷新机制有关,也可能跟多层代理机制有关。RaphaelIntegration 在 Spring 容器初始化时,已经注入了原始的 RegulatedUserAddressSnapshotQueryForSPService Bean,即使后续通过 @MockBean 创建了 Mock 对象,RaphaelIntegration 内部的引用仍指向原始 Bean;而对于 dubbo 接口(而 Dubbo 接口的实现原理就是动态代理),Spring 可能为其创建了动态代理,导致 @MockBean 无法直接覆盖。

解决办法

怎么才能让这个 mock 的 bean 在长链路中一直生效呢?用下面的写法:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = BgMoriaApplication.class)
@ActiveProfiles("test")
@WebAppConfiguration
@Slf4j
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {TigerConcurrentConsumer.class, TigerMessageProducer.class}
))
public abstract class BaseApiTest {@Autowiredprivate ApplicationContext ctx;@MockBeanprivate RegulatedUserAddressSnapshotQueryForSPService mockServicepublic void mockRegulatedQueryAddressEmptyResponse() {Mockito.when(mockService.queryAddressInfoForPaymentScene(any())).thenReturn(buildEmptyBaseResponse(QueryAddressSnapshotResponse.class));ReflectionTestUtils.setField(ctx.getBean(RaphaelIntegration.class),"regulatedUserAddressSnapshotQueryForSPService",mockService);}
}

上面的写法实际上就是用 mock 的 bean 强制覆盖上下文中的 bean,这样你在调用RaphaelIntegration 时,里面的regulatedUserAddressSnapshotQueryForSPService 就是 mock 的 bean。

进阶

那如果对于同一个接口 service 下面的多个接口,我想让 A 按自己 mock 的结果返回,而让 B 进行真实调用,这又如何实现呢?

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = BgMoriaApplication.class)
@ActiveProfiles("test")
@WebAppConfiguration
@Slf4j
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {TigerConcurrentConsumer.class, TigerMessageProducer.class}
))
public abstract class BaseApiTest {@Resource@Qualifier("regulatedUserAddressSnapshotQueryForSPService")private RegulatedUserAddressSnapshotQueryForSPService realService;private RegulatedUserAddressSnapshotQueryForSPService mockService = Mockito.mock(RegulatedUserAddressSnapshotQueryForSPService.class);;@Autowiredprivate ApplicationContext ctx;public void mockRegulatedQueryAddressMobileNullResponse() {Mockito.when(mockService.queryAddressRealMobileForPaymentScene(any())).thenReturn(null);ReflectionTestUtils.setField(ctx.getBean(RaphaelIntegration.class),"regulatedUserAddressSnapshotQueryForSPService",mockService);}public void mockRegulatedQueryAddressRealResponse() {Mockito.when(mockService.queryAddressInfoForPaymentScene(any())).thenAnswer(inv -> realService.queryAddressInfoForPaymentScene(inv.getArgument(0)));ReflectionTestUtils.setField(ctx.getBean(RaphaelIntegration.class),"regulatedUserAddressSnapshotQueryForSPService",mockService);}
}

如上所示,通过 thenAnswer 的方式来动态路由 mock 的路线,从而实现同一个 service 下的不同接口有不同的表现。


文章转载自:

http://aBvEasDH.jcfdk.cn
http://3fntJAW4.jcfdk.cn
http://YioFfa0u.jcfdk.cn
http://Lk4mORwa.jcfdk.cn
http://cRZMTw5d.jcfdk.cn
http://iQRyrj3G.jcfdk.cn
http://YkKHVXzY.jcfdk.cn
http://VVtCT3F2.jcfdk.cn
http://bioCiYIK.jcfdk.cn
http://adTPyYde.jcfdk.cn
http://i03YFvY6.jcfdk.cn
http://IZn27mSD.jcfdk.cn
http://zuqwpw5p.jcfdk.cn
http://C34gHKa5.jcfdk.cn
http://U7l9IdKW.jcfdk.cn
http://Z2NvLrhp.jcfdk.cn
http://F54zatgi.jcfdk.cn
http://jRgV5f5m.jcfdk.cn
http://g0fpIblp.jcfdk.cn
http://ZuOLdGAk.jcfdk.cn
http://ohmgTqVI.jcfdk.cn
http://mK8dHrBa.jcfdk.cn
http://Tp8HvwLs.jcfdk.cn
http://UZ24J0Q7.jcfdk.cn
http://Pw7xUzO0.jcfdk.cn
http://y9gmNrDc.jcfdk.cn
http://A7WTvTWf.jcfdk.cn
http://2kjB8dVi.jcfdk.cn
http://iJANCAVf.jcfdk.cn
http://OdpePp6g.jcfdk.cn
http://www.dtcms.com/wzjs/759535.html

相关文章:

  • 俄文淘宝网站建设现货黄金什么网站可以做直播
  • 站酷设计网站官网入口下载外省住房和城乡建设厅网站
  • 太原房产网站建设百度网站的设计风格
  • 网站地址是什么网页版微信扫一扫在哪
  • 企业网站怎样做seo优化 应该如何做齐齐哈尔企业网站排名优化
  • 公司建站模版做外贸网站怎么设计
  • 世界各大网站搜索引擎提交入口哪个厂家的广州网站建设
  • 装企工长网站开发推盟
  • 浙江省建设局教育网站东莞网站建设 南城石佳
  • 佛山响应式网站公司免费素材库app图片
  • 自己做的网站怎么设置文件下载网站布局规划怎么写
  • 网站百度地图生成器在县城做团购网站
  • 上海做网站的公司是什么网站建设过时了
  • 网站广告如何做小程序推广赚佣金
  • 网站推广结束语山西省吕梁市天气
  • 万网 手机网站网站权重最高
  • 网站建设以后就业方向德阳市做网站
  • 学习网站的建设网站建设个人信息英文翻译
  • 外贸网站cms网站开发前端与后端区别
  • 大连房地产网站开发做网站运营这工作怎么样
  • 如何把网站做成软件58同城二手房
  • 毕业设计做网站可以用模版吗徐州百姓网招聘信息网
  • 学做美食网站短视频素材免费
  • 嘉兴网站制作维护家具网站建设规划
  • 做淘客网站需要企业的域名五一自学网免费教程官网
  • 北海网站设计公司企业网站主页设计图
  • 合肥做网站推广的公司广州网络推广有限责任公司
  • 建设一个网站的步骤有哪些广州seo教程
  • 做电影网站挣钱吗wordpress 一直崩溃
  • 网站部署到终端机怎么做网站上线倒计时 模板