我有一个带有静态构造函数的类,我用它来读取 app.config 值。如何对具有不同配置值的类进行单元测试。我正在考虑在不同的应用程序域中运行每个测试,因此我可以为每个测试执行静态构造函数 - 但我在这里有两个问题:
1.我不知道如何在单独的应用程序域中运行每个测试运行
2.如何在运行时更改配置设置?
有人可以帮我吗?或者有人有更好的解决方案吗?谢谢。
我有一个带有静态构造函数的类,我用它来读取 app.config 值。如何对具有不同配置值的类进行单元测试。我正在考虑在不同的应用程序域中运行每个测试,因此我可以为每个测试执行静态构造函数 - 但我在这里有两个问题:
1.我不知道如何在单独的应用程序域中运行每个测试运行
2.如何在运行时更改配置设置?
有人可以帮我吗?或者有人有更好的解决方案吗?谢谢。
如果您从 读取(Web)ConfigurationManager.AppSettings
,那只是一个 NameValueCollection,因此您可以将ConfigurationManager.AppSettings
直接读取的代码替换为从任何 NameValueCollection 读取的代码。
只需将您的实际配置解析从静态 ctor 移至静态方法即可。静态 ctor 调用该静态方法并通过ConfigurationManager.AppSettings
,但您可以从测试代码中调用该解析器方法,并验证配置解析而无需实际接触文件或弄乱应用程序域。
但从长远来看,确实按照 seldary 的建议注入您的配置参数。创建一个配置类,在应用程序启动时读取实际值,并设置您的 IoC 容器以向所有请求者提供相同的配置实例。
这也使进一步的测试更容易,因为您的类不会从全局静态配置实例中读取。您可以只传递特定的配置实例以进行不同的测试。当然为你的测试创建一个工厂方法,来构建一个全局配置,所以你不必一直手动做......
您无需测试 .Net 是否能够从配置文件加载数据。
相反,试着专注于测试你自己的逻辑。
更改您的类,使其从其构造函数(或通过属性)获取配置值,然后像使用任何其他依赖项一样对其进行测试。
在此过程中,您还将班级移向SRP。
根据配置加载 - 将此逻辑集中在一个单独的非静态类中。
编辑:
将配置逻辑分离到另一个类中。像这样的东西:
public static class ConfigurationLoader
{
static ConfigurationLoader()
{
// Dependency1 = LoadFromConfiguration();
// Dependency2 = LoadFromConfiguration();
}
public static int Dependency1 { get; private set; }
public static string Dependency2 { get; private set; }
}
然后,当您实例化您的类时,将其注入依赖项:
public class MyClass
{
private readonly int m_Dependency1;
private readonly string m_Dependency2;
public MyClass(int dependency1, string dependency2)
{
m_Dependency1 = dependency1;
m_Dependency2 = dependency2;
}
public char MethodUnderTest()
{
if (m_Dependency1 > 42)
{
return m_Dependency2[0];
}
return ' ';
}
}
public class MyClassTests
{
[Fact]
public void MethodUnderTest_dependency1is43AndDependency2isTest_ReturnsT()
{
var underTest = new MyClass(43, "Test");
var result = underTest.MethodUnderTest();
Assert.Equal('T', result);
}
}
...
var myClass = new MyClass(ConfigurationLoader.Dependency1, ConfigurationLoader.Dependency2);
您可以继续使用 IOC 容器,但是通过这种简单的可测试设计解决了使用不同输入测试 MyClass 的问题。
就个人而言,我只会将您的静态构造函数放入静态方法中,然后在静态块中执行该方法。
我最近遇到了同样的问题。唯一的区别是配置值来自数据库而不是 app.config。我能够使用 TypeInitializer 解决它。
[Test]
public void TestConfigurationInStaticConstructor()
{
// setup configuraton to test
// ...
// init static constructor
ReaderTypeInit();
// Assert configuration effect
// ...
// reset static ctor to prevent other existing tests (that may depend on original static ctor) fail
ReaderTypeInit();
}
// helper method
private void ReaderTypeInit()
{
typeof(< your class with static ctor>).TypeInitializer.Invoke(null, new object[0]);
}