无法使用ConfigurationManager在C#.NET Core单元测试项目中读取app.config

Bro*_*ymb 19 c# unit-testing app-config .net-core

我创建了一个简单的单元测试项目来读取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>
Run Code Online (Sandbox Code Playgroud)

单元测试

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

控制台应用程序

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);
        }
    }
}  
Run Code Online (Sandbox Code Playgroud)

鉴于我仍然是整个.NET Core世界的新手,我在这里做了一些完全错误的事情吗?我此刻感到很疯狂......

这两个项目都带有app.config

小智 15

.CORE 3.1 为了找出正在使用的 dll.config 文件,我通过添加这一行并查看值是什么来调试测试。

string path = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath;
Run Code Online (Sandbox Code Playgroud)

然后我发现 resharper 使用的是 testhost.dll.config 而 VStest 使用的是 testhost.x86.dll.config。我需要将以下行添加到项目文件中。

  <Target Name="CopyCustomContent" AfterTargets="AfterBuild">
    <Copy SourceFiles="app.config" DestinationFiles="$(OutDir)\testhost.dll.config" />
    <Copy SourceFiles="app.config" DestinationFiles="$(OutDir)\testhost.x86.dll.config" />
  </Target>
Run Code Online (Sandbox Code Playgroud)

  • testhost.x86.dll.config 也是我的 net core 3.0 项目所需的名称。这也适用于重命名 app.config -&gt; testhost.x86.dll.config 并将复制到输出目录属性设置为始终复制。 (3认同)

Pau*_*her 10

查看github问题的评论,我发现可以在msbuild文件中找到解决方法...

<Target Name="CopyCustomContent" AfterTargets="AfterBuild">
  <Copy SourceFiles="app.config" DestinationFiles="$(OutDir)\testhost.dll.config" />
</Target>
Run Code Online (Sandbox Code Playgroud)

这使得在将配置数据移植到json配置文件之前,更容易在.NET Core下验证现有测试。

  • 不确定这是否特定于 VS 2022(现在是 64 位),但对于撰写本文时(2022 年 4 月)的 ReSharper 和 VS 版本,配置文件必须命名为“ReSharperTestRunner.dll.config” `(第 64 号)使其正常工作。希望有人觉得这很有用。 (5认同)
  • 我爱你宝贝 (2认同)

3DP*_*ner 9

如果您检查呼叫结果 ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

它应该告诉您在运行该程序集的单元测试时所需的配置文件应该在哪里。

我发现app.configConfigurationManager不在寻找文件,而不是在寻找testhost.dll.config文件。

这是针对netcoreapp2.1Microsoft.NET.Test.SdkNUnit 3.11Nunit3TestAdapter 3.12.0

  • 注意:除了将其从 app.config 重命名为 testhost.dll.config 以使其工作之外,我还必须将文件属性“复制到输出目录”设置为“始终复制”。感谢您的重命名提示! (2认同)

Mar*_*rio 7

我在xunit测试中遇到了相同的问题,并通过使用ConfigurationManager中的Configuration实例解决了该问题。我先将其静态(正常)方式应用于核心框架(而不是单元测试),然后再展示其在所有三种方式中均可使用的替代方式:

        var appSettingValFromStatic = ConfigurationManager.AppSettings["mySetting"];
        var appSettingValFromInstance = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).AppSettings.Settings["mySetting"].Value;
Run Code Online (Sandbox Code Playgroud)

这是一个类似/相关的问题。如果任何人都需要获得一个部分,您可以做类似的事情,尽管类型必须在应用程序配置中更改:

<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>
Run Code Online (Sandbox Code Playgroud)

代码获取部分:

        var valFromStatic = ((NameValueCollection)ConfigurationManager.GetSection("customNameValueSectionHandlerSection"))["customKey"];
        var valFromInstance = ((AppSettingsSection)ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).GetSection("customAppSettingsSection")).Settings["customKey"].Value;
Run Code Online (Sandbox Code Playgroud)

我觉得自己也很疯狂,而且我知道在内核中有更新的配置方法,但是如果有人想跨平台做某事,那是我唯一知道的方法。如果有人有其他选择,我会很感兴趣


Moo*_*tom 5

当您处理直接访问静态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 库。


Dan*_*iel 5

对于我的混合 .NET-Core 和 .NET-Framework 项目,我将以下内容添加到单元测试全局设置中:

#if NETCOREAPP
using System.Configuration;
using System.IO;
using System.Reflection;
#endif

...

// In your global setup:
#if NETCOREAPP
    string configFile = $"{Assembly.GetExecutingAssembly().Location}.config";
    string outputConfigFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath;
    File.Copy(configFile, outputConfigFile, true);
#endif
Run Code Online (Sandbox Code Playgroud)

testhost.dll.config会将配置文件复制到输出路径,但应该具有足够的弹性以应对测试框架中的未来更改。

或者你可以复制到下面,这相当于同样的事情:

string outputConfigFile = Path.Combine(Path.GetDirectoryName(configFile), $"{Path.GetFileName(Assembly.GetEntryAssembly().Location)}.config");
Run Code Online (Sandbox Code Playgroud)

感谢@stop-cran 和@PaulHatcher 的解决方案,这是两者的结合。


小智 5

当我们回答这样一个经过充分研究和明确阐述的问题时,我们最好假设它是由一个见多识广、聪明的人提出的。我们不应该用显而易见的新的、伟大的方法来编写大量的样板代码来解析各种 JSON 等,强迫我们并被知识渊博的人强加给我们,我们应该专注于回答要点。

由于 OP 已经用于System.Configuration访问设置,因此他们已经知道如何到达这一点。唯一缺少的是一点点:将这一行添加到构建后事件中:

copy $(OutDir)<appname>.dll.config $(OutDir)testhost.dll.config
Run Code Online (Sandbox Code Playgroud)

其中 <appname> 是正在单元测试的项目。

我赞扬每个仍在使用(最初是蹩脚但可行)实施的人,app.config因为这样做可以保护我们和我们的客户对技术的投资,而不是重新发明轮子。阿门。