Spring的Mock测试你用上了吗?

发表于:2020-11-20 10:00

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:RareXray 窝牛    来源:知乎

  在真实的测试当中,并不能所有的逻辑都可以自己控制,因此有了mock测试。今天就结合场景来讲一下怎么做mock测试。
  适合对象:初次尝试集成和使用mockito进行单元测试的开发同学
  Mock框架的集成
  这里选择的是Mockito + PowerMockito。为什么会集成PowerMockito,是因为有个想要mock的方法是static方法。这个需要PowerMockito,假如都只是普通类,就可以不用了。
  集成关键点如下
  1、版本对应:这两个mockito的版本是有一个对应关系,假如不对应,会出现类找不到的情况。比如 ClassNotFound org/mockito/mockitoframework 。
  这是我的集成版本:
  <dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-core</artifactId>
  <version>2.28.2</version>
  <scope>test</scope>
  </dependency>
  <dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-module-junit4</artifactId>
  <version>2.0.2</version>
  <scope>test</scope>
  </dependency>
  <dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-api-mockito2</artifactId>
  <version>2.0.2</version>
  <scope>test</scope>
  </dependency>
  2、注解方式集成:因为使用spring boot的项目,所以考虑怎么用注解方式集成。最后我的注解方案如下所示:
  @RunWith(PowerMockRunner.class)
  @PrepareForTest({JdbcClient.class})
  @PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
  @PowerMockIgnore({"javax.net.ssl.*","javax.management.*", "javax.security.*", "javax.crypto.*"})
  这几个,都有自己的用处,分别说下:
  · @RunWith(PowerMockRunner.class) :假如要使用powermock,那就需要配置这个,不然powermock无法使用
  · @PrepareForTest({JdbcClient.class}) :这里的列表,设定的是需要static mock 的类,我的测试场景中,需要mock JdbcClient的static query 方法
  · @PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class) : 一开始,只配置了前两个,然后发现从spring中inject注入的service都为空了。原来要需要使用这个注解,这样就和spring test 组合上了
  · @PowerMockIgnore({"javax.net.ssl.*","javax.management.*",
"javax.security.*","javax.crypto.*"}) :PowerMock大概是mock的太多了,所以假如没有这行注释,也是各种报错。 ClassCastException: class sun.security.provider.ConfigFile 这种。
TIPS:这些注解可以写到一个abstract TestClass 上,后面的测试类继承这个就方便了
  Mock场景举例
  好,正式开始mock。首先来讲,网上那些例子,好多都太简单了,不能当做实际场景。比如mock ClassA.method1,然后直接验证method1的结果。这种只能验证集成的对不对。还是结合真实场景比较好。
  场景一:修改外部服务调用,比如调用支付宝支付,或者发个短信什么的,也可以是数据库查询
  有时候,我们不希望真的去调用外部(比如配置太复杂,比如收费,比如想模拟错误结果)。或者想自己控制数据库查询结果(或者遇到了我这边只有正式环境才有某个库的情况)。那这时候,就需要使用Mock Service来解决。
  先撸代码,再分析。
  这个场景讲解mock的常规使用手法
  以及在spring注入service情况下,如何处理mock
  public class MockitoTest extends BaseTest {
      @Autowired
      DemoService demoService;
      @Mock
      RemoteService remoteService;
      @Test
      public void testHack() throws Exception {
          demoService.setRemoteService(remoteService);
          String result = "fail";
          Mockito.when(remoteService.sendRequest(any())).thenReturn(result);
          String callResult = demoService.callRemote("something");
          assertEquals("fail", callResult);
          Mockito.verify(remoteService).sendRequest(any());
      }
  }
  这个场景感觉用的挺多的。demoService是想要测试的功能,其中用到了remoteService.sendRequest的结果。而又不想实际调用remoteService。这时候就可以先把remoteService.sendRequest给mock掉,给出自己设定的返回结果。
  这时候要注意的一个点是:remoteService并不归属springContext管理,所以run test 以后,会发现,这个mock毫无作用。debug之下,可以看到注入和mock的remoteService并不是一个实例。
  那如何使remoteSerivce变成mockService,这里有两个思路。
  一、就是上面的方案,用mockSerivce去替换demoSerivce里的remoteService。
  demoService.setRemoteService(remoteService);
  二、替换springContext里面的remoteSerice,这就需要使用@MockBean 这个注解。 然后,所有注入的remoteService,都是Mock生成的service
      @MockBean
      RemoteService remoteService;
  但是据说MockBean有副作用,会多次重启Spring context。可能也会污染上下文。暂时没有去尝试研究。
  场景二:修改静态类方法,比如一些单例的方法。
  在我的场景里,是自定义了一个单例JdbcClient,client保存连接池,然后发起请求。
  这个是使用PowerMockito,因为只有他能mock static方法
  先来代码:
  public class MockitoTest extends BaseTest { 
      @Autowired
      DemoService demoService;
      @Test
      public void testHack() throws Exception {
          String result = "fail";
          PowerMockito.mockStatic(JdbcClient.class);
          Mockito.when(JdbcClient.sendRequest(any())).thenReturn(result);
          String callResult = demoService.callRemote("something");
          assertEquals("fail", callResult);
      }
  }
  这里的主要用法就是 PowerMockito.mockStatic 这个。但是要结合之前的两个注解,@RunWith(PowerMockRunner.class) @PrepareForTest({JdbcClient.class}) 这个使用才有效。
  就写这两个场景吧。后续用到比较好的场景再补充,也欢迎大家提供更多使用场景一起学习学习。

  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号