使用Groovy进行Java的单元测试

▼魔方 西西 提交于 2020-04-26 06:06:47
      • 为什么用Groovy写单元测试

        它与Java 平台无缝的集成,它是基于 Java 的语言(不像其他语言,是对 JRE 的替代,因此可能基于旧版的处理器),对于 Java 开发人员来说,Groovy 意味着一条短得让人难以置信的学习曲线。而且一旦将这条学习曲线拉直,Groovy 就能提供一个无与伦比的快速开发平台。

        从这个角度来说,Groovy 成功的秘密,在于它的语法 就是 Java 语法,但是规则更少。例如,Groovy 不要求使用分号,变量类型和访问修饰符也是可选的。而且,Groovy 利用了标准的 Java 库,这些都是您已经很熟悉的,包括 Collections 和 File/IO。而且,您还可以利用任何 Groovy 提供的 Java 库,包括 JUnit。

        事实上,令人放松的类 Java 语法、对标准 Java 库的重用以及快捷的生成-运行周期,这些都使 Groovy 成为快速开发单元测试的理想替代品。



      • 如何使用Groovy进行Mock测试

        用Groovy进行Mock要比JMockit之类的简单很多,下面举例还演示如何使用

        待测试类  折叠源码
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        @Slf4j
        public  class  ObjectDataController  implements  IObjectDataController {
           @Resource
           ObjectDescribeServiceImpl objectDescribeService;
           @Resource
           ObjectDataProxy objectDataProxy;
           @Resource
           LayoutServiceImpl layoutService;
         
           @Override
           public  FcpServiceResult findById(FindObjectDataArg arg) {
             if  (validateArg(arg)) {
               return  FCPUtils.buildFcpServiceResult( null , Status.CODE_ERROR, Status.MESSAGE_PARAMETER_IS_NULL,  null );
             }
             try  {
               IObjectDescribe describe;
         
               describe = getObjectDescribeInstance(arg, arg.getObject_describe_id(), arg.getObject_describe_apiname(), Id.parse(arg.getObject_describe_id()));
               if  ( null  == describe) {
                 return  FCPUtils.buildFcpServiceResult( null , Status.CODE_NOT_FOUND, Status.MESSAGE_NOT_FOUND,  null );
               }
         
               IObjectData objectData = objectDataProxy.findById(Id.parse(arg.getObject_data_id()), describe.getTenantId(), describe.getApiName());
               return  getFcpServiceResult(arg, describe, objectData);
             catch  (Exception e) {
               log.error( "find object data err. tenant_id:{},object_describe_id:{}, object_data_id:{}" , arg.getEnterpriseId(), arg.getObject_describe_id(), arg.getObject_data_id(), e);
               return  FCPUtils.buildFcpServiceResult( null , Status.CODE_ERROR, Status.MESSAGE_ERROR, e);
             }
           }
         
           private  FcpServiceResult getFcpServiceResult(FindObjectDataArg arg, IObjectDescribe describe, IObjectData objectData) {
             if  ( null  == objectData) {
               return  FCPUtils.buildFcpServiceResult( null , Status.CODE_NOT_FOUND, Status.MESSAGE_NOT_FOUND,  null );
         
             else  {
               ILayout layout =  null ;
               if  (arg.isInclude_layout()) {
                 layout = layoutService.findDefault(describe.getApiName(), arg.getEnterpriseId());
                 if  ( null  == layout) {
                   return  FCPUtils.buildFcpServiceResult( null , Status.CODE_NOT_FOUND, Status.MESSAGE_NOT_FOUND,  null );
                 }
               }
               return  FCPUtils.buildFcpServiceResult(FCPResult.builder().objectDescribe(((ObjectDescribe) describe).getContainerDocument()).objectData(objectData).layout(layout !=  null  ? ((Layout) layout).getContainerDocument() :  null ).build(), Status.CODE_OK, Status.MESSAGE_OK,  null );
             }
           }
          
           private  IObjectDescribe getObjectDescribeInstance(FindObjectDataArg arg, String object_describe_id, String object_describe_apiname, Id parse) {
             IObjectDescribe describe;
             if  (Strings.isNullOrEmpty(object_describe_id)) {
               describe =
                 objectDescribeService.findByTenantIdAndObjectDescribeApiName(arg.getEnterpriseId(), object_describe_apiname);
             else  {
               describe = objectDescribeService.findById(arg.getEnterpriseId(), parse);
             }
             return  describe;
           }
        }


        我们需要测试ObjectDataController中的findById方法, 在findById方法中用到了ObjectDescribeService, objectDataProxy和 layoutService, 我们需要把这三个实例的对应方法mock掉来测试各种返回结果下的代码处理逻辑。

        在mock这些class之前,首先需要保证ObjectDataController中有对应的三个实例的setter方法,如下代码所示

        对应的setter方法  折叠源码
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        @Override
        public  void  setObjectDataService(ObjectDataProxy proxy) {
           this .objectDataProxy = proxy;
        }
         
        @Override
        public  void  setObjectDescribeService(ObjectDescribeServiceImpl objectDescribeService) {
           this .objectDescribeService = objectDescribeService;
        }
         
        @Override
        public  void  setLayoutService(LayoutServiceImpl layoutService) {
           this .layoutService = layoutService;
        }

         

        实现了对应的setter方法后,我们就可以写unitTest了,最后的代码如下所示

        单元测试类  折叠源码
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        @RunWith (SpringJUnit4ClassRunner. class )
        @ContextConfiguration (value =  "classpath:applicationContext.xml" )
        class  ObjectDataFCPTest {
           @Autowired
           IObjectDataController objectDataController
          
           @Test
           public  void  test_find_by_id_success()  throws  Exception {
             def data = [
               getEnterpriseId      : { -> test_tenant_1 },
               getUserId            : { -> user_id },
               getObject_data_id     : { -> id },
               getObject_describe_id :{ -> id}
             ] as FindObjectDataArg
         
             def mock = [findById: {Id id, String eid, String api -> after}] as ObjectDataProxy
             objectDataController.setObjectDataService(mock)
         
             def mockDescribe = [findById: { String tenantId, Id id -> describe },
                               findByTenantIdAndObjectDescribeApiName : {String tenantId, String apiName -> describe}] as ObjectDescribeServiceImpl
             objectDataController.setObjectDescribeService(mockDescribe)
         
             FcpServiceResult result = objectDataController.findById(data);
             FCPResult fcpResult = (FCPResult)result.getResult();
             ObjectData config = (ObjectData) fcpResult.objectData
             assertEquals(test_tenant_1, config.getTenantId())
             assertEquals(id, config.getId().strValue())
             assertEquals( "example" , config.getPackage())
             assertEquals( "客户数据" , config.getName())
             assertEquals( false , config.isDeleted())
             assertEquals( 1 , config.getVersion())
             assertEquals(user_id, config.getCreatedBy())
             assertEquals(user_id, config.getLastModifiedBy())
           }
        }

         

        最后的代码因为传入参数没有包含layout部分, 所以没有mock layoutService的对应方法, 整个mock过程就是这么简单。如果你想更深入的了解groovy的单元测试实现,可以了解下spock框架

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!