app.config没有加载.Net Core MSTests项目

时间:2017-12-11 11:47:39

标签: c# .net-core

我正在尝试将一些项目从.NET Framework 4.5.2移植到.NET Core 2,而我正在尝试读取遗留应用程序单元测试中的.config appsettings。为了将问题减少到最低限度的再现方案,我在VS2017中创建了以下项目:

enter image description here

我有app.config文件:

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

和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"]);
        }
    }
}

在构建此项目时,将生成SimpleTestsUnits.dll,并使用SimpleTestsUnits.dll文件的同一文件夹中的app.config文件的内容创建SimpleTestsUnits.dll.config。

因此,当我使用VS2017运行单元测试时,&#34; TestKey&#34;总是为null,如果我调试到ConfigurationManager.AppSettings,那里没有加载密钥。

  

抛出异常:   &#39; Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException&#39;   在Microsoft.VisualStudio.TestPlatform.TestFramework.dll中   类型   &#39; Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException&#39;   发生在Microsoft.VisualStudio.TestPlatform.TestFramework.dll但是   未在用户代码中处理Assert.AreEqual失败。预期:其中20。   实际:≤(NULL)&GT;

我在这里缺少什么?难道这不起作用吗?

3 个答案:

答案 0 :(得分:11)

执行测试时,条目程序集不是包含测试的程序集。您可以通过在测试中添加以下行并进行调试来检查它:

var configLocation = Assembly.GetEntryAssembly().Location;

就我而言,configLocationc:\Users\myusername\.nuget\packages\microsoft.testplatform.testhost\15.3.0-preview-20170628-02\lib\netstandard1.5\testhost.dll

因此ConfigurationManager期望在指定目录的app.config找到testhost.dll.config。我已经将它复制到这个位置并且测试通过了(稍微修改了配置,见下文)。

另一个问题是你的app.config不完全正确。 configSections元素应该是<configuration>根中的第一个元素。因此,只需删除configSections元素,因为它是空的,或者按以下方式调整app.config

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

当然,将配置文件放在testhost.dll附近是一种不好的方法。您可以使用ConfigurationManager调用更改ConfigurationManager.OpenExeConfiguration加载应用程序配置的路径:

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

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

但不幸的是,这种方法需要修改您的测试代码。

答案 1 :(得分:3)

我相信,只要有一个非常简单的解决方案就能在不修改被测代码的情况下起作用,那么正确接受的答案会使事情复杂化。

MSTest作为testhost.dll运行,这意味着在.NET核心下执行时,ConfigurationManager正在从testhost.dll.config读取设置。它将查找testhost.dll所在的testhost.dll.config作为接受的答案状态。没有提到的是,它还会在您拥有测试dll的位置中查找testhost.dll.config。

因此将资源管理器中的原始.config文件复制或重命名为testhost.dll.config将解决此问题。

通过在“项目”标签内的MSTest .csproj文件的末尾添加以下MSBuild步骤,可以轻松实现此自动化。

<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>

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

答案 2 :(得分:0)

您可以尝试使用此类来确定大小。

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;
    }
}