当我在特定代码库中编写测试时,我经常需要在新添加的代码之前设置静态属性,并在离开时重新设置它。实施例
public void SomeMethod(){
val oldVal = Notifier.DoNotify;
Notifier.DoNotify = false;
// Some code...
Notifier.DoNotify = oldVal;
}
我认为这种方式很难看,我想要更好的东西,这也会让你更难忘记重新设定价值。
我尝试做点什么,然后得到了这个。我看到了一些好处,但这是一个非常有说服力的解决方案。
public class ValueHolder<T> : IDisposable
{
private readonly Action<T> setter;
private readonly T oldVal;
public ValueHolder(Func<T> getter, T tempVal, Action<T> setter)
{
this.setter = setter;
oldVal = getter();
setter(tempVal);
}
public void Dispose()
{
setter(oldVal);
}
}
然后使用
public void SomeMethod(){
using(new ValueHolder<bool>(() => Notifier.DoNotify, false, (b) => Notifier.DoNotify(b)) {
// Do something ...
}
}
对此有什么好处?
(编辑删除了对测试的引用。似乎分散了我想要的注意力)
答案 0 :(得分:2)
您可以采取一些措施使其更容易编写。我会尝试利用您正在使用的任何测试框架来帮助在测试之前和之后运行一些设置/清理代码。但是这里禁止一些可以减少锅炉板的技巧。
首先,我们可以创建一个辅助类,它将在样板上减少一点,以创建ValueHolder<T>
实例。我将使用LINQ表达式自动创建getter和setter委托,而不是要求getter和setter中的调用者传递(尽管在高级情况下这仍然有用)。
public class ValueHolder
{
public static ValueHolder<T> Create<T>(Expression<Func<T>> staticProp, T tempVal)
{
var ex = (MemberExpression)staticProp.Body;
var prop = (PropertyInfo)ex.Member;
var getter = (Func<T>)Delegate.CreateDelegate(typeof(Func<T>), prop.GetGetMethod());
var setter = (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), prop.GetSetMethod());
return new ValueHolder<T>(getter, tempVal, setter);
}
}
这使得创作更加简洁
ValueHolder.Create(() => Notify.DoNotify, false);
其次,您可能需要设置其中的一些,并且大量使用有点难看。我对此问题的answer提供了一种方法,可以使用从List<T>
继承的类(也是IDisposable
)稍微更轻松地处理此方案。结合这些可以使您的设置更简单:
public void SomeTestMethod()
{
// before any state has change.
using (Setup())
{
// Test code.
}
// the cleanup code has run so the state is reset here.
}
private static IDisposable Setup()
{
return new DisposableList() {
ValueHolder.Create(() => Notify.DoNotify, false),
ValueHolder.Create(() => ConnectionManager.MaxConnections, 100),
ValueHolder.Create(() => SomeClass.SomeProp, 2.5),
// etc., I think you get the idea.
};
}