【问题标题】:Not able to Mock Java method call using Spock无法使用 Spock 模拟 Java 方法调用
【发布时间】:2019-11-25 10:20:01
【问题描述】:

我正在尝试使用 Spock 模拟我的以下 java 方法。


        public List<DiffEntry> listDifferences(String oldCommit, String newCommit, Git git)
          throws GitAPIException, RevisionSyntaxException, AmbiguousObjectException,
          IncorrectObjectTypeException, IOException {

        logger.info(
            "Inside DiffCommits#listDifferences to calculating difference commits refs {}  and {} ",
            oldCommit, newCommit);

        ObjectId oldTree = git.getRepository().resolve(oldCommit);
        ObjectId newTree = git.getRepository().resolve(newCommit);

        if (oldTree == null || newTree == null) {
          logger.warn(
              "Could not resolve either old {} or new commits {}, difference cant not be calculated",
              oldCommit, newCommit);
          throw new RefNotFoundException("Unable to resolve tag reference. Invalid tag provided");
        }

        ObjectReader reader = git.getRepository().newObjectReader();
        CanonicalTreeParser oldTreeIter = new CanonicalTreeParser();
        oldTreeIter.reset(reader, oldTree);

        CanonicalTreeParser newTreeIter = new CanonicalTreeParser();
        newTreeIter.reset(reader, newTree);

        DiffFormatter df = new DiffFormatter(new ByteArrayOutputStream());

        df.setRepository(git.getRepository());
        List<DiffEntry> entries;
        entries = df.scan(newTreeIter, oldTreeIter);
        df.close();

        if (logger.isDebugEnabled()) {
          for (int i = 0; i < entries.size(); i++) {
            logger.debug("Entry: " + entries.get(i));
          }
        }

        return entries;
      }

一切正常,但以下代码的模拟失败

DiffFormatter df = new DiffFormatter(new ByteArrayOutputStream());

处出现错误
df.setRepository(git.getRepository());

我得到的错误是

> org.eclipse.jgit.lib.StoredConfig$$EnhancerByCGLIB$$9a2f8398 cannot be
> cast to org.eclipse.jgit.diff.DiffConfig java.lang.ClassCastException:
> org.eclipse.jgit.lib.StoredConfig$$EnhancerByCGLIB$$9a2f8398 cannot be
> cast to org.eclipse.jgit.diff.DiffConfig  at
> org.eclipse.jgit.diff.DiffFormatter.setReader(DiffFormatter.java:201)
>   at
> org.eclipse.jgit.diff.DiffFormatter.setRepository(DiffFormatter.java:180)
>   at
> com.sf.bt.mdm.subscription.scmdiff.DiffCommits.listDifferences(DiffCommits.java:65)
>   at com.sf.bt.mdm.subscription.service.DiffCommitSpec.test list
> differences(DiffCommitSpec.groovy:59)

我们将不胜感激任何形式的帮助

【问题讨论】:

  • 将其传递给您的方法,或将其设为您通过构造函数传递的类变量。这样你可以传递一个模拟,你的方法将使用模拟。
  • @Bentaye 还有其他方法吗?
  • 请发布您遇到的错误。
  • @Bentaye 错误更新有问题

标签: java spock


【解决方案1】:
DiffFormatter df = new DiffFormatter(new ByteArrayOutputStream());

从单元测试的角度来看,这段代码是有问题的。它不是依赖项,因此不能注入到类中。所以基本上你试图模拟一个构造函数(new)对象。

从技术上讲,您可以尝试的唯一方法是使用 Global Mocks 并创建包裹真实对象的间谍:阅读documentation。这些不是常规 spock 的 Mocks 和 Stubs。

但我相信还有其他方法。毕竟我发给你的链接都是从“使用前三思而后行”开始的;)

  1. 您自己决定将此对象创建放在方法中,这没关系。但是,这意味着您不会将此 DiffFormatter 视为真正的依赖项。所以也许即使在单元测试中你应该让它运行,专注于模拟它的输入参数本身? ByteArrayOutputStream 也是如此。这通常与代码应该以单元测试不应该真正关心方法的内部实现的方式编写的概念很好地配合。总是喜欢黑盒测试而不是白盒测试。

  2. 或者,如果您认为它是一个依赖项,那么也许您应该将其设为数据字段。然后,您可以使用常规模拟将其注入测试。如果这个类应该在每个方法调用时创建,你可以注入Supplier&lt;DiffFormatter&gt; and in method 只需调用它的get方法,它将充当工厂。

【讨论】:

  • 全局模拟将适用于被测 Java 代码,仅适用于 Groovy 代码。应根据您的建议重构被测类以获得更好的可测试性,以使依赖项可注入或至少将其创建分解为可存根的辅助方法。否则,必须使用像 PowerMock 这样的工具,而 IMO 会产生代码异味。
猜你喜欢
  • 2016-03-04
  • 1970-01-01
  • 2017-06-29
  • 2019-08-29
  • 1970-01-01
  • 2021-11-20
  • 1970-01-01
  • 1970-01-01
  • 2018-10-09
相关资源
最近更新 更多