简体   繁体   English

app.config 未加载到 .Net Core MSTests 项目中

[英]app.config not beeing loaded in .Net Core MSTests project

I'm working on a project were I'm trying to port several libraries from .NET Framework 4.5.2 to .NET Core 2, and I'm facing some problems trying to read legacy app.config appsettings in unit tests.我正在做一个项目,我正在尝试将几个库从 .NET Framework 4.5.2 移植到 .NET Core 2,并且我在尝试读取单元测试中的遗留 app.config appsettings 时遇到了一些问题。 To reduce the problem to a bare minimum reproduction scenario I've created the following project in VS2017:为了将问题减少到最低限度的再现场景,我在 VS2017 中创建了以下项目:

在此处输入图像描述

I have the app.config file:我有 app.config 文件:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="TestKey" value="20" />
  </appSettings>
  <configSections>
  </configSections>
</configuration>

And the UnitTest1.cs file:和 UnitTest1.cs 文件:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Configuration;

namespace SimpleTestsUnits
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void FromConfigurationManager()
        {
            Assert.AreEqual("20", ConfigurationManager.AppSettings["TestKey"]);
        }
    }
}

And upon building this project the SimpleTestsUnits.dll is generated and the SimpleTestsUnits.dll.config is created with the content of the app.config file in the same folder of the SimpleTestsUnits.dll file.在构建此项目时,将生成 SimpleTestsUnits.dll,并使用与 SimpleTestsUnits.dll 文件相同文件夹中的 app.config 文件的内容创建 SimpleTestsUnits.dll.config。

So, when I run the unit test using VS2017 the value of "TestKey" is always null and if I debug into the ConfigurationManager.AppSettings there is no key loaded there.因此,当我使用 VS2017 运行单元测试时,“TestKey”的值始终为 null,如果我调试到 ConfigurationManager.AppSettings,则那里没有加载密钥。

Exception thrown: 'Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException' in Microsoft.VisualStudio.TestPlatform.TestFramework.dll An exception of type 'Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException' occurred in Microsoft.VisualStudio.TestPlatform.TestFramework.dll but was not handled in user code Assert.AreEqual failed.抛出的异常:Microsoft.VisualStudio.TestPlatform.TestFramework.dll 中的 'Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException'但未在用户代码中处理 Assert.AreEqual 失败。 Expected:<20>.预期:<20>。 Actual:<(null)>.实际:<(空)>。

What am I missing here?我在这里错过了什么? Shouldn't this be working?这不应该工作吗?

MSTest is running as "testhost.dll", which means that ConfigurationManager is reading settings from "testhost.dll.config" when executing under .NET core. MSTest 作为“testhost.dll”运行,这意味着 ConfigurationManager 在 .NET core 下执行时正在从“testhost.dll.config”读取设置。 It will look for "testhost.dll.config" where the "testhost.dll" is located but it will also also look for "testhost.dll.config" in the location where you have your test dlls.它会在“testhost.dll”所在的位置查找“testhost.dll.config”,但它还会在您拥有测试 dll 的位置查找“testhost.dll.config”。

So copying or renaming your config file in explorer to "testhost.dll.config" will solve the problem.因此,将资源管理器中的配置文件复制或重命名为“testhost.dll.config”将解决问题。

You can easily automate this by adding the following MSBuild step to the end of the MSTest .csproj file, within the "Project" tag.您可以通过将以下 MSBuild 步骤添加到 MSTest .csproj 文件末尾的“项目”标记中轻松实现此操作。

<Target Name="CopyAppConfig" AfterTargets="Build" DependsOnTargets="Build">
    <CreateItem Include="$(OutputPath)$(AssemblyName).dll.config">
         <Output TaskParameter="Include" ItemName="FilesToCopy"/>
    </CreateItem>
    <Copy SourceFiles="@(FilesToCopy)" DestinationFiles="$(OutputPath)testhost.dll.config" />
</Target>

Source: ( https://github.com/Microsoft/testfx/issues/348#issuecomment-454347131 )来源:( https://github.com/Microsoft/testfx/issues/348#issuecomment-454347131

When you execute the tests, the entry assembly is not an assembly with your tests.当您执行测试时,入口程序集不是包含您的测试的程序集。 You can check it by adding following line to your test and debugging it:您可以通过在测试中添加以下行并调试来检查它:

var configLocation = Assembly.GetEntryAssembly().Location;

In my case configLocation was c:\\Users\\myusername\\.nuget\\packages\\microsoft.testplatform.testhost\\15.3.0-preview-20170628-02\\lib\\netstandard1.5\\testhost.dll在我的情况下configLocationc:\\Users\\myusername\\.nuget\\packages\\microsoft.testplatform.testhost\\15.3.0-preview-20170628-02\\lib\\netstandard1.5\\testhost.dll

So ConfigurationManager expects to find app.config at testhost.dll.config in specified directory.所以ConfigurationManager期望在指定目录中的testhost.dll.config中找到app.config I've copied it to this location and the test passed ok (after slight modification of the config, see below).我已经将它复制到这个位置并且测试通过了(在稍微修改配置之后,见下文)。

Another problem is that your app.config is not fully correct.另一个问题是您的 app.config 不完全正确。 configSections element should be the first in <configuration> root. configSections元素应该是<configuration>根中的第一个元素。 So just remove configSections element as it's empty or adjust your app.config in the following way:因此,只需删除configSections元素,因为它是空的,或者按以下方式调整您的app.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
  </configSections>
  <appSettings>
    <add key="TestKey" value="20" />
  </appSettings>
</configuration>

Of course, it's a bad way to place config file near testhost.dll .当然,将配置文件testhost.dll附近是一种不好的方式。 You could change the path from which ConfigurationManager loads application config with ConfigurationManager.OpenExeConfiguration call:您可以使用ConfigurationManager.OpenExeConfiguration调用更改ConfigurationManager加载应用程序配置的路径:

[TestMethod]
public void UnitTest1()
{
    //  Put your Test assembly name here
    Configuration configuration = ConfigurationManager.OpenExeConfiguration(@"SimpleTestsUnits.dll");

    Assert.AreEqual("20", configuration.AppSettings.Settings["TestKey"].Value);
}

But unfortunately this approach requires modification of your code under test.但不幸的是,这种方法需要修改您的被测代码。

You can try this class for size.你可以试试这个类的大小。

public static class AppConfig
{
    const string Filename = "app.config";

    static readonly Configuration Configuration;

    static AppConfig()
    {
        try
        {
            Configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

            if (!Configuration.HasFile)
                throw new ConfigurationErrorsException();
        }
        catch
        {
            try
            {
                var configmap = new ExeConfigurationFileMap
                {
                    ExeConfigFilename = Filename
                };

                Configuration = ConfigurationManager.OpenMappedExeConfiguration(configmap, ConfigurationUserLevel.None);
            }
            catch
            {
            }
        }
    }

    public static string Get(string key, string @default = "")
    {
        return Configuration?.AppSettings?.Settings[key]?.Value ?? @default;
    }
}

I implemented the solution that Oskar Sjöberg presented.我实施了Oskar Sjöberg提出的解决方案。 It worked well for our solutions until we began to use multi-targeting.在我们开始使用多目标之前,它适用于我们的解决方案。

The MSBuild step that Oskar presented would attempt to copy files from a location that was not being used as an output directory for building. Oskar 提供的 MSBuild 步骤将尝试从未用作 output 构建目录的位置复制文件。 It would produce an error as it could not find the app.config files that it was looking for.它会产生一个错误,因为它找不到它正在寻找的app.config文件。

I ended up adding Condition="'$(OutDir)' != ''" to the target definition.我最终将Condition="'$(OutDir)' != ''"添加到目标定义中。

Note: I have not tested this across many platforms or many project styles. It may be the case that this prevents the copying from taking place.注意:我没有在许多平台或许多项目 styles 上对此进行测试。这可能会阻止复制发生。

It then looked like this:然后看起来像这样:

<Target Name="CopyAppConfig" AfterTargets="Build" DependsOnTargets="Build" Condition="'$(OutDir)' != ''">
  <CreateItem Include="$(OutputPath)$(AssemblyName).dll.config">
    <Output TaskParameter="Include" ItemName="FilesToCopy" />
  </CreateItem>
  <Copy SourceFiles="@(FilesToCopy)" DestinationFiles="$(OutputPath)testhost.dll.config" />
</Target>

BTW I wanted to comment on that post but I do not have enough reputation yet.顺便说一句,我想对该帖子发表评论,但我还没有足够的声誉。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM