我被困在代码的这一点上,我不知道如何模仿:
ConfigurationManager.AppSettings["User"];
我必须模拟ConfigurationManager,但我没有线索,我正在使用Moq。
有人可以给我一个提示吗?谢谢!
答案 0 :(得分:136)
我正在使用AspnetMvc4。刚才我写了
ConfigurationManager.AppSettings["mykey"] = "myvalue";
在我的测试方法中,它运作得很好。
说明:测试方法在应用程序设置的上下文中运行,通常是web.config
或myapp.config
。 ConfigurationsManager
可以访问此应用程序全局对象并对其进行操作。
虽然:如果你有一个并行运行测试的测试运行器,这不是一个好主意。
答案 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 文件中拥有测试所需的值,就很容易覆盖和更改值。