如何 File.Exists 在 Nunit 测试中

Posted

技术标签:

【中文标题】如何 File.Exists 在 Nunit 测试中【英文标题】:How to File.Exists in Nunit Test 【发布时间】:2010-12-22 16:47:34 【问题描述】:

我有一种方法可以在对文件内容进行一些操作之前测试文件是否存在,如下所示:

Private Sub AddHeaderToLogFile()
    ''#Only if file does not exist
    If Not File.Exists(_logPath) Then
        Dim headerLogger As Logger
        headerLogger = LogManager.GetLogger("HeaderLogger")
        ''#Use GlobalDiagnosticContext in 2.0, GDC in pre-2.0
        NLog.GlobalDiagnosticsContext.Set("appName", _appName)
        NLog.GlobalDiagnosticsContext.Set("fileVersion", _fileVersion)
        NLog.GlobalDiagnosticsContext.Set("logId", 0)
        headerLogger.Info("")
    End If
End Sub

想法是,如果文件不存在,则通过调用 NLog 记录器实例生成文件,此时创建文件并插入指定的标头信息。该方法在应用程序本身上运行良好,但是我有一个简单的 NUnit 测试,它实现了一个测试方法来验证文件是否按预期创建和填充。当我使用调试器单步执行时,我发现 '_logPath' 设置为:

D:\Documents and Settings\TE602510\Local Settings\Temp\nunit20\ShadowCopyCache\4288_634286300896838506\Tests_-1937845265\assembly\dl3\7cdfe61a\aa18c98d_f0a1cb01\logs\2010-12-22.log

不幸的是,尽管文件确实存在,但对 File.Exists 的调用返回 false。从之前对配置路径的查看来看,上述路径对于这些 NUnit 测试似乎是正确的。有没有人知道这里发生了什么以及我需要做什么才能获得预期的结果?根据 XP 文件系统,日志文件的路径名是:

D:\Documents and Settings\TE602510\My Documents_VSSWorkArea\PsalertsIp\Tests\bin\Debug\logs

亲切的问候

保罗·J.

【问题讨论】:

对我来说听起来像是框架的错误。 【参考方案1】:

不要使用 File.Exists!

文件系统是易变的,因此您正在查找的文件的存在(或不存在)可能会在您检查和对结果采取行动之间发生变化。此外,File.Exists 不会确定您是否拥有相关文件的正确权限。

相反,您在这里要做的只是尝试正确打开文件,如下所示:

Try
    Using fs As IO.FileStream = IO.File.Open(_logPath, FileMode.CreateNew)

    End Using
Catch ex AS IOException 
    ''# This will be thrown if the file already exists - just swallow it
    ''# If you also want to handle IOExceptions while working on the file,
    ''#  place another try/catch inside the using block
End Try

File.Exists 应该只在文件的存在本身具有意义时才使用,但该文件永远不会被实际读取或写入。例如,某些主机系统会创建和销毁文件以指示锁定或指示作业完成。

【讨论】:

【参考方案2】:

可能是权限问题。从MSDN,File.Exists(path)返回:

true 如果调用者具有所需的权限并且 path 包含现有文件的名称;否则,错误。如果 path 是空引用(在 Visual Basic 中为 Nothing)、无效路径或长度为零的字符串,此方法也会返回 false。如果调用者没有足够的权限读取指定的文件,则不抛出异常,并且无论path是否存在,该方法都返回false

编辑 这里有两种方法将尝试获取目录/文件的 ACL。可能是调用 NUnit 的方式权限不同。

Private Shared Function DoesFileExist(ByVal file As String) As Boolean
    Try
        Dim FI As New System.IO.FileInfo(file)
        Dim AC = FI.GetAccessControl()              'This method will fail if the file is not found'
        Return True
    Catch ex As System.IO.FileNotFoundException     'FNF error should be thrown if it does not exist'
        Return False
    Catch ex As Exception
        'If you do not have permission to read the permissions this might throw, too.'
        'Of course, in that situation that means that the file exists so we should'
        'probably return True here, too. For debugging I am still throwing though.'
        Throw ex
    End Try
End Function
Private Shared Function DoesDirectoryExist(ByVal dir As String) As Boolean
    Try
        Dim DI As New System.IO.DirectoryInfo(dir)
        Dim AC = DI.GetAccessControl()               'This method will fail if the directory is not found'
        Return True
    Catch ex As System.IO.DirectoryNotFoundException 'DNF error should be thrown if it does not exist'
        Return False
    Catch ex As Exception
        'If you do not have permission to read the permissions this might throw, too.'
        'Of course, in that situation that means that the directory exists so we should'
        'probably return True here, too. For debugging I am still throwing though.'
        Throw ex
    End Try
End Function

【讨论】:

克里斯,感谢您的回复。在这里很难看出权限如何成为问题,所描述的路径位于我的文档文件夹结构中,有问题的文件是在运行时创建的,没有任何问题。我想这与通过 NUnit 生成路径的方式有关(即不是实际的物理路径名)...... 记住文件系统是易变的——这些方法应该使用过去时最准确地命名。 DidFileExistACoupleOfMillisecondsAgo? 您可以关闭 NUnit 卷影复制选项(并直接从调试文件夹运行测试) - 如果错误确实来自日志位置。

以上是关于如何 File.Exists 在 Nunit 测试中的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Nunit进行测试

如何迭代地运行 nunit 测试

如何在测试拆解时使用 NUnit 3 读取 ITestResult

你如何从 Jenkins 运行 NUnit 测试?

使用 NUnit 时,我应该如何在运行时修改 app.config?

运行 vstest.console.exe 时如何过滤 NUnit 测试