我创建了一个简单的单元测试项目来读取app.config文件。目标框架是Core 2.0。我还创建了一个Core 2.0控制台应用程序,以便对自己进行完整性检查,以确保我没有做任何奇怪的事情(在.NET 4.6.1单元测试项目中,同样的测试通过了预期)。
控制台应用程序读取app.config很好,但单元测试方法失败,我无法弄清楚原因。两者都使用相同app.config的副本(未添加为链接),并且都安装了System.Configuration.ConfigurationManager v4.4.1 NuGet包。
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="Test1" value ="This is test 1."/>
<add key="Test2" value ="42"/>
<add key="Test3" value ="-42"/>
<add key="Test4" value="true"/>
<add key="Test5" value="false"/>
<add key="Test6" value ="101.101"/>
<add key="Test7" value ="-1.2345"/>
</appSettings>
</configuration>
单元测试
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Configuration;
namespace ConfigTest
{
[TestClass]
public class UnitTest1
{
[TestMethod()]
public void ConfigTest()
{
foreach (string s in ConfigurationManager.AppSettings.AllKeys)
{
System.Console.WriteLine(s);
System.Diagnostics.Debug.WriteLine(s);
}
//AllKeys.Length is 0? Should be 7...
Assert.IsTrue(ConfigurationManager.AppSettings.AllKeys.Length == 7);
}
}
}
控制台应用程序
using System;
using System.Configuration;
namespace ConfigTestApp
{
class Program
{
static void Main(string[] args)
{
foreach (string s in ConfigurationManager.AppSettings.AllKeys)
{
Console.WriteLine(s);
System.Diagnostics.Debug.WriteLine(s);
}
//Outputs 7 as expected
Console.WriteLine(ConfigurationManager.AppSettings.AllKeys.Length);
}
}
}
鉴于我仍然是整个.NET Core世界的新手,我在这里做了一些完全错误的事情吗?我此刻感到很疯狂......
我遇到了与xunit测试相同的问题,并使用ConfigurationManager中的Configuration实例解决了这个问题。在我展示它在三者中起作用的替代方式之前,我把静态(正常)方式放在核心,框架(但不是单元测试)中:
var appSettingValFromStatic = ConfigurationManager.AppSettings["mySetting"];
var appSettingValFromInstance = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).AppSettings.Settings["mySetting"].Value;
这是一个类似/相关的问题。如果任何人需要获得一个部分你可以做类似的事情,虽然类型必须在应用程序配置中更改:
<configSections>
<section name="customAppSettingsSection" type="System.Configuration.AppSettingsSection"/>
<section name="customNameValueSectionHandlerSection" type="System.Configuration.NameValueSectionHandler"/>
</configSections>
<customAppSettingsSection>
<add key="customKey" value="customValue" />
</customAppSettingsSection>
<customNameValueSectionHandlerSection>
<add key="customKey" value="customValue" />
</customNameValueSectionHandlerSection>
抓取部分的代码:
var valFromStatic = ((NameValueCollection)ConfigurationManager.GetSection("customNameValueSectionHandlerSection"))["customKey"];
var valFromInstance = ((AppSettingsSection)ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).GetSection("customAppSettingsSection")).Settings["customKey"].Value;
我觉得我也疯了,我知道有更新的方法在核心中进行配置,但如果想要跨平台做某事,这是我知道的唯一方法。如果有人有其他选择,我会很感兴趣
如果你检查调用ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
的结果
它应该告诉您在运行该程序集的单元测试时所需的配置文件应该在哪里。
我发现没有一个app.config
文件,ConfigurationManager正在寻找一个testhost.dll.config
文件。
这是针对netcoreapp2.1
的项目,参考Microsoft.NET.Test.Sdk
,NUnit 3.11
和Nunit3TestAdapter 3.12.0
ConfigurationManager
API仅使用当前运行的应用程序的配置。在单元测试项目中,这意味着测试项目的app.config,而不是控制台应用程序。
.NET Core Applications不应该使用app.config或ConfigurationManager
,因为它是一个传统的“完整框架”配置系统。
考虑使用Microsoft.Extensions.Configuration
来读取JSON,XML或INI配置文件。请参阅此文档:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration
当您处理代码直接访问静态ConfigurationManager
属性(如AppSettings
或ConnectionStrings
)时,这里给出的答案都没有提供可行的解决方法。
事实是,目前是不可能的。你可以在这里阅读讨论,了解原因:https://github.com/dotnet/corefx/issues/22101
有人在这里谈论实施它的支持:https://github.com/Microsoft/vstest/issues/1758
在我看来,支持这种情况是有道理的,因为它一直在.NET Framework上工作,System.Configuration.ConfigurationManager
现在是.NET Standard 2.0库。
通过github问题的评论,我找到了一个可以进入msbuild文件的工作......
<Target Name="CopyCustomContent" AfterTargets="AfterBuild">
<Copy SourceFiles="app.config" DestinationFiles="$(OutDir)\testhost.dll.config" />
</Target>
这样可以在将配置数据移植到json配置文件之前更轻松地验证.NET Core下的现有测试。
通常在.NET Framework项目中,任何App.config文件都由Visual Studio复制到bin文件夹,并带有可执行文件的名称(myApp.exe.config),因此可以在运行时访问它。不再是.NET Standard或Core Framework。您必须手动复制并设置bin / debug或release文件夹中的文件。在那之后它可以得到类似的东西:
string AssemblyName = System.IO.Path.GetFileName(System.Reflection.Assembly.GetEntryAssembly().GetName().CodeBase);
AppConfig = (System.Configuration.Configuration)System.Configuration.ConfigurationManager.OpenExeConfiguration(AssemblyName);
一种hacky,但工作方式是将配置复制到与条目程序集相同的文件夹,无论它是什么:
[SetUpFixture]
public class ConfigKludge
{
[OneTimeSetUp]
public void Setup() =>
File.Copy(
Assembly.GetExecutingAssembly().Location + ".config",
Assembly.GetEntryAssembly().Location + ".config",
true);
[OneTimeTearDown]
public void Teardown() =>
File.Delete(Assembly.GetEntryAssembly().Location + ".config");
}
除了添加这个类之外,唯一让它工作的是在测试项目中包含app.config
文件(没有任何复制选项)。它应该在构建步骤中作为<your test project name>.dll.config
复制到输出文件夹,因为它是一种默认逻辑。
请注意OneTimeSetUpAttribute
的文档:
摘要:标识在运行任何子测试之前调用一次以执行设置的方法。
虽然它应该适用于单个项目的并行测试运行,但是同时运行两个测试项目时可能会遇到明显的麻烦,因为配置会被覆盖。
但是,它仍然适用于容器化测试,例如Travis。