web-dev-qa-db-fra.com

Impossible de lire app.config dans le projet de test d'unité C # .NET Core avec ConfigurationManager

J'ai créé un projet de test unitaire simple pour lire un fichier app.config. Le cadre cible est Core 2.0. J'ai également créé une application pour console Core 2.0 afin de vérifier que je ne faisais rien de bizarre (même test réussi comme prévu dans un projet de test unitaire .NET 4.6.1). 

L'application de la console lit très bien app.config, mais la méthode de test unitaire échoue et je ne peux pas comprendre pourquoi. Les deux utilisent une copie du même fichier app.config (non ajouté en tant que lien) et le package System.Configuration.ConfigurationManager v4.4.1 NuGet est installé. 

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

Le test unitaire 

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

L'application de la console 

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

Étant donné que je suis encore assez nouveau dans le monde .NET Core, est-ce que je fais quelque chose de totalement incorrect ici? Je me sens un peu fou en ce moment ... 

 Both projects with an app.config

10
Broots Waymb

Je suis tombé sur le même problème avec mes tests xunit et je l'ai résolu en utilisant l'instance de Configuration from ConfigurationManager. Je mets la manière statique (normale) de travailler dans le cadre, le framework (mais pas les tests unitaires) avant de montrer la manière alternative de travailler dans les trois:

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

Et voici un problème similaire/connexe. Si quelqu'un a besoin d'une section, vous pouvez faire la même chose, mais le type doit changer dans la configuration de l'application:

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

Code pour saisir la section:

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

Je me sens aussi fou, et je sais qu’il existe de nouvelles méthodes de configuration en noyau, mais si on veut faire quelque chose sur plusieurs plates-formes, c’est le seul moyen que je connaisse. Je serais très intéressé si quelqu'un a des alternatives

3
Mario

Si vous vérifiez le résultat de l'appel à ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

Il devrait vous indiquer où se trouve le fichier de configuration requis lors de l'exécution de tests unitaires pour cet assemblage. 

J'ai constaté qu'au lieu d'avoir un fichier app.config, ConfigurationManager recherchait un fichier testhost.dll.config

C'était pour un projet ciblant netcoreapp2.1, avec une référence à Microsoft.NET.Test.Sdk, NUnit 3.11 et Nunit3TestAdapter 3.12.0 

2
3DPrintScanner

L'API ConfigurationManager utilisera uniquement la configuration de l'application en cours d'exécution. Dans un projet de test unitaire, cela signifie que le fichier app.config du projet de test, pas l'application console.

Les applications .NET Core ne sont pas censées utiliser app.config ou ConfigurationManager, car il s'agit d'un système de configuration hérité du "framework complet".

Utilisez plutôt Microsoft.Extensions.Configuration pour lire les fichiers de configuration JSON, XML ou INI. Voir cette doc: https://docs.Microsoft.com/en-us/aspnet/core/fundamentals/configuration

2
Martin Ullrich

Généralement, dans les projets .NET Framework, tous les fichiers App.config étaient copiés dans le dossier bin par Visual Studio, avec le nom de votre exécutable (myApp.exe.config) afin de pouvoir être atteints au moment de l'exécution. Plus maintenant dans .NET Standard ou Core Framework. Vous devezmanuellementcopier et définir le fichier dans le dossier bin/debug ou release. Après cela, cela pourrait être obtenu avec quelque chose comme: 

                string AssemblyName = System.IO.Path.GetFileName(System.Reflection.Assembly.GetEntryAssembly().GetName().CodeBase);
            AppConfig = (System.Configuration.Configuration)System.Configuration.ConfigurationManager.OpenExeConfiguration(AssemblyName);
0
Fidel Orozco

Aucune des réponses données ici ne fournit une solution de contournement viable lorsque vous utilisez du code qui accède directement aux propriétés statiques ConfigurationManager telles que AppSettings ou ConnectionStrings.

La vérité est que ce n'est pas possible pour le moment. Vous pouvez lire la discussion ici pour comprendre pourquoi: https://github.com/dotnet/corefx/issues/22101

On parle de mettre en place le support pour cela ici: https://github.com/Microsoft/vstest/issues/1758

À mon avis, il est logique de prendre en charge ce scénario car il fonctionne sur le .NET Framework plus System.Configuration.ConfigurationManager est maintenant une bibliothèque .NET Standard 2.0.

0
MoonStom

Un hacky, mais une méthode de travail consiste à copier la configuration dans le même dossier qu’une entrée Assembly, quelle qu’elle soit:

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

Outre l'ajout de cette classe, la seule chose à faire pour que cela fonctionne est d'inclure le fichier app.config dans le projet test (sans aucune option de copie). Il devrait être copié dans le dossier de sortie en tant que <your test project name>.dll.config à l'étape de construction, car c'est une sorte de logique par défaut.

Notez la documentation pour OneTimeSetUpAttribute:

Résumé: Identifie une méthode appelée une fois pour effectuer la configuration avant l'exécution de tout test enfant.

Bien que cela devrait fonctionner pour des tests en parallèle pour un seul projet, des problèmes évidents peuvent survenir lors de l'exécution simultanée de deux projets de test, car la configuration serait écrasée.

Cependant, il est toujours adapté aux tests en conteneur, comme dans Travis .

0
stop-cran