.NetCore技术研究-ConfigurationManager在单元测试下的坑

Posted tianqing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了.NetCore技术研究-ConfigurationManager在单元测试下的坑相关的知识,希望对你有一定的参考价值。

最近在将原有代码迁移.NET Core, 代码的迁移基本很快,当然也遇到了不少坑,重构了不少,后续逐步总结分享给大家。今天总结分享一下ConfigurationManager遇到的一个问题。

先说一下场景:

   迁移.NET Core后,已有的配置文件,我们希望做到兼容,比如说app.config和web.config,

   这样配置文件尽可能地和.NET Framework是一套,尽可能低保持一致。比如:appSettings自定义configSection等等。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="CustomConfigs" type="ClassLibraryNetStandard.CustomConfigHandler, ClassLibraryNetStandard"/>
  </configSections>
  <CustomConfigs>
    <CustomConfig name="service1" order="0" reflectconfig="ClassLibraryNetStandard.TestService, ClassLibraryNetStandard"/>
    <CustomConfig name="service2" order="1" reflectconfig="ClassLibraryNetStandard.TestService2, ClassLibraryNetStandard"/>
  </CustomConfigs>  
  <appSettings>
    <add key="service" value="service1"/>
  </appSettings>
</configuration>

 对于上面配置读取我们做了以下几个事情

   1. 添加Nuget:System.Configuration.ConfigurationManager

   2. 保证原有自定义Section配置相关的代码、读取配置的代码,迁移到.NET Core后编译通过

   3. 修改配置文件、单元测试

 一、添加Nuget:System.Configuration.ConfigurationManager

   搜索System.Configuration.ConfigurationManager:找到Nuget包,并添加引用:

   技术图片

二、保证原有自定义Section配置相关的代码、读取配置的代码,迁移到.NET Core后编译通过

  示例代码中,自定义配置类CustomConfig

using System;
using System.Collections.Generic;
using System.Text;

namespace ClassLibraryNetStandard

    public class CustomConfig
    
        public string Name  get; set; 

        public string ReflectConfig  get; set; 

        public int Order  get; set; 
    

  同时对应的Section配置节解析类:CustomConfigHandler,实现接口:System.Configuration.IConfigurationSectionHandler

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace ClassLibraryNetStandard

   public class CustomConfigHandler : System.Configuration.IConfigurationSectionHandler
    
        public object Create(object parent, object configContext, XmlNode section)
        
            var configs = new List<CustomConfig>();

            //获取配置文件中自定义节点值  
            foreach (XmlNode childNode in section.ChildNodes)
            
                string name = null;
                var config = new CustomConfig();
                if (childNode.Attributes["name"] != null)
                
                    name = childNode.Attributes["name"].Value;
                    config.Name = name;

                    if (childNode.Attributes["order"] != null)
                    
                        config.Order = Convert.ToInt32(childNode.Attributes["order"].Value);
                    
                    if (childNode.Attributes["reflectconfig"] != null)
                    
                        config.ReflectConfig = childNode.Attributes["reflectconfig"].Value;
                                      

                    configs.Add(config);
                
            

            return configs;
        
    

    同时,我们编写了一个简单的配置管理类:CustomConfigManager,其中有配置读取方法,直接读取配置文件:

        public static List<CustomConfig> GetCustomConfigs()
        
            var sectionConfig = System.Configuration.ConfigurationManager.GetSection("CustomConfigs");
            if (sectionConfig != null)
            
                return  sectionConfig as List<CustomConfig>;
            

            return null;
        

  

  这里我们使用了.NET Standard 2.0 library project,代码编译通过:

技术图片

1>------ 已启动全部重新生成: 项目: ClassLibraryNetStandard, 配置: Debug Any CPU ------
1>C:\\Program Files\\dotnet\\sdk\\3.0.100-preview3-010431\\Sdks\\Microsoft.NET.Sdk\\targets\\Microsoft.NET.RuntimeIdentifierInference.targets(151,5): message NETSDK1057: 你正在使用 .NET Core 的预览版。请查看 https://aka.ms/dotnet-core-preview
1>ClassLibraryNetStandard -> C:\\Users\\***\\source\\repos\\NETFrameworkTest\\ClassLibraryNetStandard\\bin\\Debug\\netstandard2.0\\ClassLibraryNetStandard.dll
========== 全部重新生成: 成功 1 个,失败 0 个,跳过 0 个 ==========

   三、修改配置文件、单元测试

  添加MSTest单元测试工程:   

  技术图片

   增加App.config配置文件:

   技术图片

   在单元测试方法中测试配置的读取:

       [TestMethod]
        public void ConfigTest()
        
            var configs = ClassLibraryNetStandard.CustomConfigManager.GetCustomConfigs();
            Assert.IsNotNull(configs);
        

  原本以为,肯定可以获取到配置,实际获取的configs是null。

        换了个Console类的应用,同样的配置文件读取,一点没有问题:

      技术图片

      对比看了一下这两个工程,发现除了实际编译生成的配置文件名称不同,其他都一样。

      问题肯定出在了单元测试工程上。Google了一下:有以下发现:       

MSTest is running as testhost.dll, which means that ConfigurationManager is reading settings from testhost.dll.config when executing under .NET core. 
It will look for testhost.dll.config where the testhost.dll is located as the accepted answer states.
What is not mentioned is that it will also look for testhost.dll.config in the location where you have your test dlls.

  一句话:MSTest以testhost.dll运行,去取的配置文件是testhost.dll.config

        这太尴尬了,直接无语,不过有两个解决方案:

        1. 直接在单元测试工程中将app.config文件改为:testhost.dll.config

        2. 修改单元测试工程文件,配置编译后事件,动态copy生成testhost.dll.config

       技术图片

      试过之后,果真可以了,问题解决,分享个大家。

 

 

周国庆

2019/9/12

以上是关于.NetCore技术研究-ConfigurationManager在单元测试下的坑的主要内容,如果未能解决你的问题,请参考以下文章

.NetCore技术研究-一套代码同时支持.NET Framework和.NET Core

.NET Core技术研究-中间件的由来和使用

.NetCore中间件源码研究

netcore.exe是啥cpu使用率高

Consider defining a bean of type ‘com.example.springbootdemo.mapper.UserMapper‘ in your configuratio

Consider defining a bean of type ‘com.example.springbootdemo.mapper.UserMapper‘ in your configuratio