我们使用 Xunit 进行测试。我们使用 Xunit 插件通过内置的 Visual Studio 2013 Test Runner 运行测试。
问题是一些测试需要引用文件系统上的文件。似乎 Xunit(或 VS Test Runner - 不确定是哪个)在执行测试之前将汇编文件(而不是 bin 目录中的任何支持文件)复制到另一个目录,因此找不到我们的测试文件。 [MS 测试框架指定了列出要复制的文件的属性,但 Xunit 没有。]
如何禁用此复制行为,或者以编程方式确定原始
bin/
目录位置来获取文件?
大多数提出的解决方案(包括 Xunit 错误跟踪网站上的解决方案)似乎都建议将文件存储为嵌入式资源,而不是“始终复制”文件。然而,这并不总是实用,例如:测试文件操作代码,以及(在一种情况下)需要 Sqlite 数据库文件的代码。
经过一番搜索,我在这里找到了解决方案:https://msdn.microsoft.com/en-us/library/ms182475.aspx.
特别是,第一步对我来说已经足够了:
如果它们特定于一个测试项目,请将它们作为内容文件包含在 Visual Studio 测试项目中。在解决方案资源管理器中选择它们,并将“复制到输出”属性设置为“如果较新则复制”。
与以下代码相关联:
var filename = "./Resources/fake.pdf";
var stream = File.OpenRead(filename);
好吧,典型的,我一发布问题,我自己就找到了答案......
要点是程序集的复制(影子复制)似乎是由 .NET 框架完成的,而不是由 Visual Studio 或 Xunit 完成的。
我们一直在使用
Assembly.Location
来定位程序集文件,从而找到测试文件。然而,这是错误的,因为它为我们提供了卷影复制组件的位置而不是原始组件的位置。
您应该使用
Assembly.CodeBase
来获取基本汇编代码位置。但是,这是一个(文件)URL,因此需要从 URL 中提取路径。新的 (C#) 代码如下所示:
var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().CodeBase);
var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);
var dirPath = Path.GetDirectoryName(codeBasePath);
return Path.Combine(dirPath, relativePath);
...其中
relativePath
是相对于 Bin\
目录的路径。
从
.NET5
(也许更早)开始,CodeBase
不再起作用,因此现在的解决方案是首先将所有文件复制到 bin 目录,并将其用作您的已知位置。
现在可以了,这在过去总是很痛苦,因为您可以轻松地从
csproj
文件将目录复制到 bin 文件夹。
<ItemGroup>
<None
Include="TestFiles\**"
CopyToOutputDirectory="PreserveNewest"
LinkBase="TestFiles\" />
</ItemGroup>
其中
TestFiles
位于项目文件夹的根目录中。现在您可以使用以下辅助方法访问这些文件。
public static class TestUtils
{
public static string GetTestPath(string relativePath)
{
var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().Location);
var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);
var dirPath = Path.GetDirectoryName(codeBasePath);
return Path.Combine(dirPath, "TestFiles", relativePath);
}
}
在努力尝试识别目录和复制文件之后(似乎有多个目录在起作用,很难确定正确的目录),我发现你可以关闭卷影复制;此时,单元测试将再次引用 bin/{configuration} 文件夹中的内容。
为此,请按照此处的说明进行操作。看起来就像将
shadowCopy
设置为 false 一样简单:
{
"shadowCopy": false
}
我不清楚此设置是否与其他设置有任何不利的相互作用(例如
appDomain
)。如果有人知道,欢迎评论。
我在 Mac 上运行 .Net Core 1.0。
Assembly.GetExecutingAssembly
不可用。我使用以下代码代替:
var location = typeof(YourClassName).GetTypeInfo().Assembly.Location;
var dirPath = Path.GetDirectoryName(location);
return Path.Combine(dirPath, relativePath);
relativePath
是相对于 DLL 目录的路径。