zoukankan      html  css  js  c++  java
  • 使用Groovy进行Java的单元测试

        • 为什么用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框架

  • 相关阅读:
    Codeforces932E. Team Work
    BZOJ2956: 模积和
    Codeforces932D. Tree
    51nod1040 最大公约数之和
    伯努利数
    BZOJ3456: 城市规划
    BZOJ4555: [Tjoi2016&Heoi2016]求和
    Codeforces936C. Lock Puzzle
    BZOJ3771: Triple
    SPOJ LCS2 后缀自动机
  • 原文地址:https://www.cnblogs.com/ljsong/p/8692909.html
Copyright © 2011-2022 走看看