乐趣区

关于单元测试:mockito入门

前言

最近在我的项目中跑单元测试发现间接应用 springboot 自带的测试,一整套跑起来破费数十分钟,这是无法忍受的,思考到性能的特殊性,想到了 Spring 测试包自带的 mockito 单元测试,所以进行首次尝试应用。

测试代码

pom 包

   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
   </dependency>

   <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-inline</artifactId>
      <version>4.5.1</version>
      <scope>test</scope>
   </dependency>
   import org.springframework.beans.factory.annotation.Autowired;
   import org.springframework.stereotype.Service;

   /**
    * @author Steven
    * @Date 2023/1/30 15:45
    */
   @Service
   public class OrderA {

       @Autowired
       private OrderC orderC;

       public int print() {System.out.println("D ="+ OrderD.getResult());
           System.out.println(orderC.print(2));
           System.out.println("hello world");
           return -1;
       }

   }

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;

    /**
     * @author Steven
     * @Date 2023/1/30 15:46
     */
    @Service
    public class OrderB {

        @Autowired
        private OrderA order;

        public boolean test() {System.out.println("order B test()");
            System.out.println("order value =" + order.print());
            System.out.println("order B hello world");
            return true;
        }

    }

    import org.springframework.stereotype.Service;

    /**
     * @author Steven
     * @Date 2023/1/30 16:43
     */
    @Service
    public class OrderC {public int print(int a) {System.out.println("hello"+ a);
            return -1;
        }
    }

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;

    /**
     * @author Steven
     * @Date 2023/1/30 17:32
     */
    @Component
    public class OrderD {
        private static OrderC orderC;

        @Autowired
        public OrderD(OrderC orderCa) {System.out.println("==================");
            orderC = orderCa;
        }

        public static int getResult(){System.out.println("hhhhh====" + OrderE.print());
            return orderC.print(3);
        }

    }



    /**
     * @author Steven
     * @Date 2023/1/31 14:04
     */
    public class OrderE {public static int print() {System.out.println("ahhahahahahhaha");
            return 1111111;
        }
        
    }

次要测试类


    import com.timelinecapital.web.service.order.*;
    import org.checkerframework.checker.units.qual.A;
    import org.junit.jupiter.api.Assertions;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.mockito.MockedStatic;
    import org.mockito.Mockito;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.mock.mockito.MockBean;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit.jupiter.SpringExtension;

    import static org.mockito.ArgumentMatchers.anyInt;
    import static org.mockito.BDDMockito.then;
    import static org.mockito.Mockito.when;

    /**
     * @author Steven
     * @Date 2023/1/30 15:48
     */
    @ContextConfiguration(classes = {OrderB.class, OrderA.class, OrderC.class, OrderD.class})
    @ExtendWith(SpringExtension.class)
    public class OrderTest {

        @Autowired
        private OrderB orderB;

        @MockBean
        private OrderC orderC;


        @Test
        public void testOrder() throws Exception {Mockito.mockStatic(OrderE.class);
    //        try (MockedStatic<OrderE> orderEMockedStatic = Mockito.mockStatic(OrderE.class)) {when(OrderE.print()).thenReturn(333);
    //            orderEMockedStatic.close();
    //        }
    //        when(orderA.print()).thenReturn(100);
    //        when(orderC.print(anyInt())).thenReturn(101);
            when(orderC.print(anyInt())).thenReturn(201);

            boolean res = orderB.test();

            Assertions.assertTrue(res);
        }


    }

测试代码阐明:


@ExtendWith(SpringExtension.class) 这个注解重要是继承 spring 的环境

        @ContextConfiguration 这个注解次要
            - classes 属性次要是导入 springbean,如果不配置须要倒入的 bean 会报依赖注入异样

默认状况须要手动配置相干须要注入 bean 的类否则会报错,依赖注入异样,找不到相应的 bean

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderB': Unsatisfied dependency expressed through field 'order'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.timelinecapital.web.service.order.OrderA' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
       at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:659)
       at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:639)
       at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)

有些工夫须要 mock 静态方法,单纯的应用 Mockito.mockStatic(OrderE.class); 会报错,须要导入 mockito-inline 包,具体起因后续剖析
常见的谬误异样有,这谬误异样很敌对都提醒了如何操作:

   org.mockito.exceptions.base.MockitoException: 
           The used MockMaker SubclassByteBuddyMockMaker does not support the creation of static mocks

           Mockito's inline mock maker supports static mocks based on the Instrumentation API.
           You can simply enable this mock mode, by placing the 'mockito-inline' artifact where you are currently using 'mockito-core'.
           Note that Mockito's inline mock maker is not supported on Android.

总结

默认状况下须要手动配置绝对应的所有须要注入的 bean,但凡你这个模块须要倒入的 bean 你都须要配置,如果你不配置注入就会报错,要么注入,要么 mock,比方 OrderB 外面依赖了 OrderA 和一个动态的 OrderD 类,OrderA bean 要么 mock 要么注入,OrderD 就不一样了因为是动态的,然而导入的时候须要注入 OrderC 所以站在 Spring 的角度,都须要注入。当然也能够一开始就 mock,当一个实例被 mock 之后他就成虚构的了,他的依赖就不须要进行注入了。
站在我的项目的角度,我的项目越大不可能为了某个性能跑一次服务,因为服务还有其余性能,所以功能测试就成了很好的解决方案,你能够随便的 mock,返回想要的值,最大角度的笼罩所有测试,惟一的毛病是,你须要思考所有的依赖注入。

援用

应用 Mockito 模仿 Static 静态方法 https://blog.csdn.net/qq_3864…

退出移动版