【问题标题】:Unit Testing code that creates directories创建目录的单元测试代码
【发布时间】:2016-07-01 08:41:36
【问题描述】:

我有创建目录并将文件传输到其中的代码。我想对它进行单元测试。但问题是当我运行单元测试时,这些目录被创建,但我不希望这样。我希望代码仅在运行生产环境时创建这些目录。我对此进行了谷歌搜索,但所有搜索结果都建议使用 JUnit 类 TemporaryFolder。但这不是我想要的。我没有在我的测试用例中创建目录。我只是在测试创建它们的代码。所以我不确定 TemporaryFolder 类如何帮助我。说我有如下代码

public class Util {

    public File getLocation(String location) {
        File result = new File(location);

        if (!result.exists()) {
            result.mkdirs(); 
        }
        return result;
    }
}

如何对此类代码进行单元测试?每次打电话

util.getLocation("base/location"); 

正在创建目录基/位置,但我不希望这样。它们应该只在我在生产环境中运行代码时创建。

更新 由于问题上的cmets。我决定更新我的问题。首先,getLocation 签名有点误导。那不是我正在测试的确切代码,它有点长,所以我试图用它来传达这个想法。它的功能基本相同,但问题是 getLocation() 没有参数,如上所示。在 getLocation 内部调用了另一个方法,该方法将字符串返回到路径。这意味着我无法控制创建目录时使用的内容。而且我同时运行生产和开发环境,一旦在运行生产代码时创建了这些目录,即使重新构建代码也不应该删除它们,因为单元测试将在每次构建时运行。

public File getLocationForReports() {

    String softwareHome = GeneralUtil.getSoftwareHome();
    File path = new Path(softwareHome, "reports").toFile();

    if (!path.exists()) {
        path.mkdirs();    
    }
    return path;
}

正如您在上面看到的,我无法控制 GeneralUtil.getSoftwareHome() 返回的内容,因此我什至无法发送像“tmp/location”这样的虚拟位置并稍后删除,我也不想删除这些目录,如果它们是在运行生产代码时创建的,因为我会创建一些文件。

【问题讨论】:

  • 在没有 JUnits 临时文件夹的情况下唯一有意义的方法是恕我直言,通过使用 Mockito 之类的模拟框架。也许这对你有帮助:stackoverflow.com/questions/18977057/…。但是单元测试创​​建文件夹/文件的问题是什么?您可以定义在执行测试后应删除所有内容。此外,您可以使用其他/相对路径进行测试,以便在其他环境中执行
  • 在测试结束时删除它们?
  • 创建文件夹,检查是否有效,删除...
  • 当然,有时单元测试......测试代码和“什么都没有”发生是有道理的。但是见鬼:您​​说的是创建目录,之后可以轻松删除。也许这不会是一个“纯粹的”单元测试;但是,嘿:这将完美地证明您的代码正在执行您希望它执行的操作。你仍然可以运行它,它是任何 jenkins/eclipse 单元测试运行的一部分。我认为“我不希望创建目录”在这里只是“过度思考”。
  • 好的,我知道我可以创建目录并删除它们。但这也不是我想要的。我同时运行生产和开发环境。单元测试仅在构建代码时运行。在生产中,调用该方法来传输一些文件。如果我在单元测试中删除它们,它们不会影响我的生产环境。我的意思是一旦在生产环境中创建了这些目录。无论我重建代码多少次,它们都不应该被删除。

标签: java unit-testing junit


【解决方案1】:

我建议尽你所能使用 PowerMock 进行任何测试。

PowerMock 操纵您的生产类;它通常会导致非常奇怪的错误(你可以追查几个小时,却从未在代码中发现真正的问题);它会扼杀你的报道能力。

换句话说:对我来说,PowerMock 的“需要”很大程度上转化为:您的设计结构不适合进行合理的测试。与其投资于又大又丑的 PowerMock 锤子……不如花时间重新设计你的设计!

在您的情况下:摆脱对静态方法的调用;确保您可以使用依赖注入来为您的代码提供模拟对象。含义:EasyMock 之类的框架允许您创建模拟对象来执行您希望它们执行的任何操作。您将此类“准备好的”模拟传递给您的测试代码;然后您就可以完全控制测试过程中发生的事情。

你看,本质上你的问题是你的生产代码在一个地方做了太多的事情;因此,您很难对其进行测试。把它拆开,把代码中的每个“责任”放到单独的类/方法中;并单独测试。

【讨论】:

    【解决方案2】:

    我建议使用 PowerMock 来创建您的测试。 有两种方法可以做到这一点。两者都需要 PowerMock 并且需要像这样注释测试: @RunWith(PowerMockRunner.class) @PrepareForTest(你要测试的类.class)

    首先,您可以尝试使用 powermockito 模拟对 GeneralUtil.getSoftwareHome() 的静态调用。 PowerMockito mock single static method and return object

    第二个选项是模拟 Path 对象的构造函数及其返回的调用: mockito mock a constructor with parameter

    这样您可以测试代码的功能。

    【讨论】:

      猜你喜欢
      • 2016-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多