【问题标题】:Unit test with files system dependency - hidden files具有文件系统依赖性的单元测试 - 隐藏文件
【发布时间】:2009-09-25 06:43:25
【问题描述】:

我正在用 Java 编写类似“Total Commander”的应用程序。这里有非常明显的文件系统依赖性。

我想对其进行单元测试。我为测试目的创建了目录结构,我将它保存在 SVN 存储库中的已知位置。到目前为止效果很好。

现在,我有一个方法可以忽略隐藏文件。我该怎么办?我可以以某种方式将文件标记为隐藏在 SVN 中吗?

其他解决方案是在运行测试之前将其中一个文件隐藏在构建脚本中,但我担心这会将文件标记为已修改并始终显示在提交对话框中。

有什么建议吗?

【问题讨论】:

    标签: java unit-testing


    【解决方案1】:

    我会将测试目录的所有初始化放入测试本身。这样的情况很简单:

    • 创建目录
    • 将一些隐藏和可见文件放入其中
    • 测试
    • 通过删除目录来拆除

    【讨论】:

    • 我怎样才能在 JUnit 4 中做到这一点?有没有办法在所有测试之前设置它并在所有测试完成后拆除?
    • @BeforeClass@AfterClass
    • 最好为每个测试而不是每个套件创建所需的目录结构,以最大程度地降低测试之间隐藏依赖关系的风险。共享声明在单元测试中是邪恶的
    • 是的,你是对的。但我确信这些测试迟早会变慢 =) 首先,使用测试级设置可能会更好。
    • @ChssPly76:我不同意。如果您正在编写验收/集成测试,则需要拥有测试数据 - 它应该与测试一起存储(即在源代码管理中),或生成(通过存储在源代码管理中的代码)。跨度>
    【解决方案2】:

    本质上,在单元测试时访问文件系统是一个很大的禁忌。对于初学者来说,这些测试比您的系统内测试慢(更慢),从而降低了您以高频率运行测试的可能性(例如每次编译时)。

    如果您使用适配器模式来抽象出对文件系统的访问,那就更好了。我是 .NET 开发人员,所以我的示例将使用 C#,但我希望您能够简单地翻译它:

    public class MyManager
    {
        private readonly IFileAdapter _fileAdapter;
        public MyManager(IFileAdapter fileAdapter)
        {
            _fileAdapter = fileAdapter;
        }
    }
    
    public interface IFileAdapter
    {
        public FileStream Open(string fileName);
        public string ReadLine(FileStream fileStream);
        // More methods...
    }
    
    public class FileAdapter : IFileAdapter
    {
        public FileStream Open(string fileName)
        {
            return System.Io.File.Open(fileName);
        }
    
        public string ReadLine(FileStream fileStream)
        {
            return File.Open(fileStream);
        }
    }
    

    现在,像往常一样,您可以模拟文件系统,就像模拟任何其他类一样,提供返回的结果。请记住 - 您是在测试 Java 的 IO 类,假设它们可以工作。您只是在测试您的类(即 MyManager,在上面的示例中)。

    将实际使用文件系统的测试留给您的集成/验收测试。

    希望这会有所帮助, 阿萨夫。

    【讨论】:

    • 我按照你的建议做了,不过有一个问题。我有负责 GUI 的类(控件布局等。其中一个需要实际的 java.io.File 来查找文件的系统图标。可以处理实际文件,而不是抽象,在应用程序的 GUI 层?反正我不会对它进行单元测试。
    • 如果你不测试GUI层,那么你真的不需要File类的抽象。但是,查找文件所需的逻辑是您可能不希望在 GUI 层中拥有的东西 - 如果我理解您的意思,它是您的问题域的一部分。因此,我会将其移至业务层。既然你想测试 BL,你应该使用适配器。 HTH,阿萨夫。
    • 我确实需要抽象,我在整个代码中都使用了 File。现在,在抽象之后,我在两个地方需要它:初始化应用程序和查找图标。其他一切,包括任何业务逻辑,都是通过抽象完成的。
    • 我非常喜欢将 GUI 层限制为没有任何逻辑。这意味着我的 GUI 层通常只有对表示层的传递调用、显示方法(即 MessageBox.Show("foo");)和初始化。一旦我发现自己放置了任何类型的逻辑(条件、循环等),它就会被提升到模型中,从而进行测试。使用该逻辑,您可以轻松决定是否应该将文件访问抽象为查找图标和初始化应用程序。
    【解决方案3】:

    我更喜欢抽象文件系统,这样我的单元测试就不需要访问真实的文件系统。当然,这个抽象层必须用真实的文件系统进行测试,但是这样可以减少对它的依赖。

    至于在 SVN 中存储隐藏文件,我是第二个 artemb。您应该创建在 JUnit 设置中进行测试所需的所有文件。据推测,您应该更喜欢按测试方法设置(@Before 和@After)。但是如果您遇到测试缓慢的问题,请查看@BeforeClass@AfterClass。我认为它们也可以与测试套件一起使用。

    【讨论】:

      【解决方案4】:

      artemb 的回答是正确的,你可以使用@Before 和@After 来为每个测试创建和删除你的结构。

      这是我用来创建包含一些文件的新目录的一些代码,它将在系统临时目录中创建目录,这很重要,因为根据您的测试将在其上运行的机器,您可能不会允许在其他地方创建文件或目录。 (我必须编写这段代码才能让我的测试在我们的 linux 集成机器上执行......)

          final String tempdir = System.getProperty("java.io.tmpdir");
          final String dirname = Long.toHexString(System.currentTimeMillis());
          final File dir = new File(tempdir, dirname);
          dir.deleteOnExit();
          dir.mkdir();
          final String path = dir.getAbsolutePath();
          assertTrue(dir.exists());
          // pre condition, the directory is empty
          assertTrue(dir.list().length == 0);
      
          // create temp files in the directory
          final int nbFiles = 3;
          for (int i = 0; i < nbFiles; i++) {
              (File.createTempFile("test", ".txt", dir)).deleteOnExit();
          }
      

      顺便说一句,您必须知道在什么平台上运行才能创建隐藏文件...

      【讨论】:

        猜你喜欢
        • 2010-09-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多