暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Java单元测试Mock工具Mockito介绍

程序员升级之路 2021-10-04
3939


一、什么是Mock&为什么要Mock

Mock就是在测试过程中对于那些不容易构建的依赖进行模拟,以保证系统的测试流程可以正常运行,即生成一个和实际使用场景不一样的对象;


为什么需要Mock呢?

1、在测试环境中构建一些依赖的成本比较高

    如一些硬件的操作,像串口和USB输入;

    还有一些第三方依赖,像支付系统要调用很多外部支付网关,如果直接调用生产环境的网关就会产生脏数据的问题;


2、分而测之

     以上面的例子来说,生产环境中就是要从硬件输入,那这块是不是不测试呢?肯定是要测试的,不过分开来测,一部分测试软件上的流程,即从硬件输入后系统的处理流程是否正常,在一些异常下数据是否准确;而硬件输入的测试可以由单独的团队测试,这样就可以并行测试提高效率。



二、Mockito介绍

Mockito是一款优秀的Mock工具,以下是其相关的介绍:

Mockito源码:

https://github.com/mockito/mockito


Mockito2.x新特性介绍:

https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2



接下来介绍Mockito的具体使用:

1、引入依赖:

    <dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>3.7.7</version>
    <scope>test</scope>
    </dependency>


    2、模拟对象

    具体的方式有2种:调用spy方法,或加Spy注解;

    先讲下我们的范例代码,假设我们有个简单的PostService,用来操作帖子的:

      public class PostService {
      @Resource
      private UserService userService;


      /**
          * 添加帖子
      * @return
      */
         public void addPost(Post post){
             User user = userService.findUser(post.getUserId());
             if (user.isDisabled()){
                 //用户被禁用
             }
         }
       }

      上面是个简单的例子,在添加帖子的时候需要调用用户服务来查询用户信息,这里不讨论代码组织是否合理,是否用到了DDD,只是一个例子说明如何使用Mockito;


      先看看spy方法如何Mock:

        import static org.mockito.Mockito.spy;


        public class PostServiceTest extends TestMain {
        @Autowired
            private UserService userService;
            
        @Test
            public void testAddPost() throws Exception {
                UserService mockUserService = spy(userService);
                Post post = new Post();
                post.setTitle("test");
                post.setAutor("Edward");
                post.setUserId(123);
                Mockito.when(mockUserService .findUser(
                Mockito.anyInt()).thenReturn(
                    new User(123, "edward", 1)
                    //用户ID,用户名,用户状态1:正常,0:禁用
                ));
        }
        }


        Spy注解

          public class PostServiceTest extends TestMain {
          @Autowired
             @Spy
             private UserService userService;

          private AutoCloseable autoCloseable;

          @BeforeClass
          public void initMock() {
          autoCloseable = MockitoAnnotations.openMocks(this);
          }
          @AfterClass
          public void close() throws Exception {
          autoCloseable.close();
          }

           }


          注意这里要调用MockitoAnnotations.openMocks,不然会报错;


          可以看到上面拦截方法调用的语法是Mockito.when(..).thenReturn

          when传方法,thenReturn传递要返回的结果,如果when要带参数,一般是这样的格式, Mockito.anyInt(),Mockito定义了很多常用类型,可以根据自己需要选择;


          3、模拟静态方法

          如果要用Mockito模拟静态方法,一是要保证Mockito包版本在3.4.0以上,二是需要额外加mockito-inline依赖,如下:

            <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-inline</artifactId>
            <version>3.7.7</version>
            <scope>test</scope>
            </dependency>

            加好依赖后,通过 Mockito.mockStatic 来模拟静态方法。





              @Test
              public void testStaticMethod() {
              LocalDate dummy = LocalDate.of(2021, 10, 4);
              try (MockedStatic<LocalDate> theMock = Mockito.mockStatic(LocalDate.class)) {
              theMock.when(LocalDate::now).thenReturn(dummy);


                      LocalDate now = LocalDate.now();
              System.out.println(now);
              Assert.assertEquals(2021, now.getYear());
              }


              }

              这里要注意dummy一定要放在mockStatic前面,因为后面一旦Mock了,所有静态方法都被Mock掉,of静态方法没有设置返回值会报错的。


              聊聊DDD的分层架构

              Codis源码分析之Slots迁移篇

              文章转载自程序员升级之路,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论