如何使用moq模拟ConfigurationManager.AppSettings

时间:2012-02-28 16:46:23

标签: c# unit-testing moq

我被困在代码的这一点上,我不知道如何模仿:

ConfigurationManager.AppSettings["User"];

我必须模拟ConfigurationManager,但我没有线索,我正在使用Moq

有人可以给我一个提示吗?谢谢!

9 个答案:

答案 0 :(得分:136)

我正在使用AspnetMvc4。刚才我写了

ConfigurationManager.AppSettings["mykey"] = "myvalue";

在我的测试方法中,它运作得很好。

说明:测试方法在应用程序设置的上下文中运行,通常是web.configmyapp.configConfigurationsManager可以访问此应用程序全局对象并对其进行操作。

虽然:如果你有一个并行运行测试的测试运行器,这不是一个好主意。

答案 1 :(得分:96)

我认为一种标准方法是使用 facade 模式来包装配置管理器,然后你就可以控制松散耦合。

所以你要包装ConfigurationManager。类似的东西:

public class Configuration: IConfiguration
{
    public User
    {
        get{ 
               return ConfigurationManager.AppSettings["User"];
       }
    }
}

(您可以从配置类中提取接口,然后在代码中的任何位置使用该接口) 然后你只需要模拟IConfiguration。您可以通过几种不同的方式实现外观。上面我选择仅包装各个属性。您还可以获得使用强类型信息而不是弱类型哈希数组的附带好处。

答案 2 :(得分:21)

可能不是您需要完成的任务,但您是否考虑在测试项目中使用app.config? 因此,ConfigurationManager将获取您在app.config中放置的值,而您无需模拟任何内容。 这个解决方案很适合我的需求,因为我从不需要测试“变量”配置文件。

答案 3 :(得分:14)

您可以使用填充程序将AppSettings修改为自定义NameValueCollection对象。以下是如何实现此目标的示例:

[TestMethod]
public void TestSomething()
{
    using(ShimsContext.Create()) {
        const string key = "key";
        const string value = "value";
        ShimConfigurationManager.AppSettingsGet = () =>
        {
            NameValueCollection nameValueCollection = new NameValueCollection();
            nameValueCollection.Add(key, value);
            return nameValueCollection;
        };

        ///
        // Test code here.
        ///

        // Validation code goes here.        
    }
}

您可以在Isolating Code Under Test with Microsoft Fakes了解更多有关垫片和假货的信息。希望这可以帮助。

答案 4 :(得分:8)

您是否考虑过抄袭而不是嘲笑? AppSettings属性为NameValueCollection

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        // Arrange
        var settings = new NameValueCollection {{"User", "Otuyh"}};
        var classUnderTest = new ClassUnderTest(settings);

        // Act
        classUnderTest.MethodUnderTest();

        // Assert something...
    }
}

public class ClassUnderTest
{
    private readonly NameValueCollection _settings;

    public ClassUnderTest(NameValueCollection settings)
    {
        _settings = settings;
    }

    public void MethodUnderTest()
    {
        // get the User from Settings
        string user = _settings["User"];

        // log
        Trace.TraceInformation("User = \"{0}\"", user);

        // do something else...
    }
}

这些好处是一个更简单的实现,并且在您真正需要它之前不依赖于System.Configuration。

答案 5 :(得分:2)

这是一个静态属性,Moq是为可以通过继承模拟的Moq实例方法或类而设计的。换句话说,Moq在这里对你没有任何帮助。

对于模拟静态,我使用一个名为Moles的工具,它是免费的。还有其他框架隔离工具,比如Typemock也可以这样做,但我相信这些是付费工具。

当谈到静力学和测试时,另一个选择是自己创建静态,虽然这通常会有问题(因为,我想你的情况就是如此)。

而且,最后,如果隔离框架不是一个选项,并且您已经致力于这种方法,那么Joshua提到的外观是一种很好的方法,或者一般的方法,您将客户端代码从业务中分离出来你用来测试的逻辑。

答案 6 :(得分:2)

仅设置所需内容怎么样?因为,我不想模拟.NET,我是否...?

System.Configuration.ConfigurationManager.AppSettings["myKey"] = "myVal";

您可能应该事先清除AppSettings,以确保该应用程序只看到您想要的内容。

答案 7 :(得分:1)

我认为编写自己的app.config提供程序是一项简单的任务,比其他任何东西都更有用。特别是你应该避免像垫片等假货,因为一旦你使用它们编辑&继续不再有效。





我使用的提供程序如下所示:





默认情况下,他们从中获取值 App.config 但是对于单元测试,我可以覆盖所有值并在每个测试中独立使用它们。





不需要任何接口或每次都一遍又一遍地实施它。我有一个实用程序DLL,并在许多项目和单元测试中使用这个小助手。




  public class AppConfigProvider
 {
 public AppConfigProvider()
 {
 ConnectionStrings = new ConnectionStringsProvider();
 AppSettings = new AppSettingsProvider();
 }

 public ConnectionStringsProvider ConnectionStrings {get;私人集; }

 public AppSettingsProvider AppSettings {get;私人集; }
}

公共类ConnectionStringsProvider
 {
 private readonly Dictionary< string,string> _customValues = new Dictionary< string,string>(StringComparer.OrdinalIgnoreCase);

 public string this [string key]
 {
让
 {
 string customValue;
 if(_customValues.TryGetValue(key,out customValue))
 {
 return customValue;
 }

 var connectionStringSettings = ConfigurationManager.ConnectionStrings [key];
 return connectionStringSettings == null? null:connectionStringSettings.ConnectionString;
 }
 }

 public Dictionary< string,string> CustomValues {get {return _customValues; 
}

公共类AppSettingsProvider
 {
 private readonly Dictionary< string,string> _customValues = new Dictionary< string,string>(StringComparer.OrdinalIgnoreCase);

 public string this [string key]
 {
让
 {
 string customValue;
 return _customValues.TryGetValue(key,out customValue)? customValue:ConfigurationManager.AppSettings [key];
 }
 }

 public Dictionary< string,string> CustomValues {get {return _customValues; 
}
  



答案 8 :(得分:0)

实现此目标的另一种方法是仅提供您自己的 IConfiguration,从您希望从中提取的任何文件中提取,如下所示:

var builder = new ConfigurationBuilder()
         .SetBasePath(Directory.GetCurrentDirectory())
         .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).Build();

现在,只要您在此 JSON 文件中拥有测试所需的值,就很容易覆盖和更改值。