【问题标题】:Writing unit tests with mocking of static methods in java在java中模拟静态方法编写单元测试
【发布时间】:2016-03-18 09:21:24
【问题描述】:

一般来说,我是编写测试的新手。我需要测试的类有一个方法,需要测试:

public String run(final Map<String, Dataset> datasets)
            throws ApiException {

        final String sourcePath = ElementsUtil.getElementFromDatasets(inputElementNames.get(0), datasets).getValue();
        final String destinationPath = ElementsUtil.getElementFromDatasets(inputElementNames.get(1), datasets).getValue();

        final File source = new File(sourcePath);
        final File destination = new File(destinationPath);

        if (source.exists()) {
            if (source.isDirectory()) {
                final IOFileFilter filter = new WildcardFileFilter(pattern);
                final Iterator<File> it = FileUtils.iterateFiles(source, filter, null);

                while (it.hasNext()) {
                    final File file = it.next();
                    moveFileToDirectory(file, destination);
                }
            } else {
                moveFileToDirectory(source, destination);
            }
        } else {
            LOGGER.error("Source file/folder at path {} doesn't exist.", sourcePath);
        }

        return "0";
    }

起初,由于我对编写单元测试的了解有限,我的单元测试看起来像这样:

@Test(description = "Test in case the source is a file.")
    public void moveFileTest1() {

        // setup
        final String fileName = UUID.randomUUID().toString() + ".txt";
        final String folderName = UUID.randomUUID().toString();
        final Element source = new Element("source", "./" + fileName);
        final Element destination = new Element("destination", "./" + folderName);

        ...

        final Path sourcePath = Paths.get(source.getValue());
        final Path destinationPath = Paths.get(destination.getValue());
        final Path fileDestination = Paths.get(destination.getValue() + "/" + fileName);
        try {
            Files.createFile(sourcePath);
            Files.createDirectory(destinationPath);

            // exercise
            moveFile.run("", datasets, null);

            // verify
            Assert.assertEquals(Files.exists(fileDestination), true);
            Assert.assertEquals(Files.exists(sourcePath), false);
        } catch (ApiException | IOException e) {
            LOGGER.error("Exception : ", e);
        } finally {

            // teardown
            try {
                Files.deleteIfExists(sourcePath);
            } catch (final IOException e) {
                LOGGER.error("Exception in teardown: ", e);
            }
            try {
                Files.deleteIfExists(fileDestination);
            } catch (IOException e) {
                LOGGER.error("Exception in teardown: ", e);
            }
            try {
                Files.deleteIfExists(destinationPath);
            } catch (IOException e) {
                LOGGER.error("Exception in teardown: ", e);
            }
        }
    }

在阅读了一些关于单元测试的文章后,我发现我的测试并不完全是在测试一个单元,因为我的方法依赖于不同的 util 方法。我还发现了在测试中模拟对象以及应该如何模拟所有内容。我的问题是:我应该在这些 util 方法/新对象调用等中使用模拟还是有不同的方法?您将如何测试这段代码?

【问题讨论】:

  • 那些Utils 对象从何而来?
  • @chrylis ElementsUtil 是我写的项目的一部分,FileUtils 是apache commons library。

标签: java unit-testing testing mocking powermock


【解决方案1】:

您所做的称为集成测试。集成测试是在不模拟任何东西的情况下测试对象/方法,对真实数据或您在测试期间产生的数据进行测试。集成测试所做的是测试您的单元、您的单元使用的单元和使用流程。如果您只想测试您的单元,您应该模拟您的单元使用的所有其他单元,并创建这些单元是否成功完成工作的流程。这意味着您应该复制一个测试,其中一个使用过的单元抛出异常/返回一个您不希望作为一个好值的值(只有当它真的可以做到时)并返回一个您确实期望的值以及现在如何工作和。 通常在编写测试时你会同时进行单元测试和集成测试

【讨论】:

    【解决方案2】:

    有一个很好的测试原则,例如“Don't Mock What You Don't Own”。这不是什么意思?这意味着你不应该模拟/存根任何你无法控制的接口,即使这个接口是由你的公司编写的,而不是你的团队编写的。

    但是如何编写单元测试,而不是集成测试,您可能想在其中模拟除正在测试的类之外的所有类?确实,这是一个非常棘手的问题。还有一个关于系统设计的答案,而不是关于测试的答案。您可以阅读herehere 如何解决该问题。

    这对你意味着什么?

    正如你提到的ElementsUtil 是你写的,所以这个类应该被嘲笑。如何?这取决于您现在正在编写的旧代码还是新代码。如果您有遗留代码 - 那么您需要PowerMock,否则您可能会更改设计并使用ElementsUtil 的实例。

    例如,将ElementsUtil类分为三个类:Elements-接口、ElementsImpl-实现、ElementsUtil-具有静态访问的类以保持兼容性。 ElementsUtil 可能有方法

    public static Elements getInstance()

    并且该方法可以被构造函数中包含run方法的类使用。但是您可以为构造函数提供参数或设置器。顺便说一句,我记得 Mockito 可以将模拟注入私有字段。在此重构之后,您不需要 PowerMock 并且只能使用 Mockito。

    现在关于FileUtils。该课程不属于您,因此如果遵循良好的做法,那么该课程应该是模拟的。但是FileUtils 与文件一起使用,它已经是集成测试了。所以回答 - FileUtils 应该被一个新的类包裹。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-12
      • 1970-01-01
      • 2019-04-04
      • 1970-01-01
      相关资源
      最近更新 更多