2

When I'm writing tests in a specific code base, I often need set a static property before my newly added code, and re-set it back when leaving. Example

public void SomeMethod(){
    val oldVal = Notifier.DoNotify;
    Notifier.DoNotify = false;

    // Some code...

    Notifier.DoNotify = oldVal;
}

I think this way is ugly and I want something nicer and which also makes it harder forget to re-set the value.

I tried cooking something up and got this. I see some benefits, but it's a pretty talky solution.

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);
    }
}

Which then is used like

public void SomeMethod(){
    using(new ValueHolder<bool>(() => Notifier.DoNotify, false, (b) => Notifier.DoNotify(b)) {

        // Do something ...
    }
}

What is a good solution to this?

(Edit removed reference to testing. Seemed to distract from what I wanted to ask)

Peteter
  • 691
  • 9
  • 25

1 Answers1

2

There's a couple things you can do to make it a little easier to write. I would try to leverage whatever testing framework you are using to help running some setup/cleanup code before and after the test. But barring that here some tips that can cut down on the boiler plate.

First we can create a helper class that will cut down a little on the boilerplate for creating a ValueHolder<T> instance. I'll use LINQ Expressions to create the getter and setter delegates automatically rather than requiring the caller pass in both a getter and setter (although that could still be useful in advanced cases).

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);
    }
}

This makes the creation a little more terse

ValueHolder.Create(() => Notify.DoNotify, false);

Second, you will probably need to set a few of these and a big using is kind of ugly. My answer to this question provides a way to handle this scenario in a slightly easier way using a class that inherits from List<T> which is also IDisposable. Combining these you could make your setup much simpler:

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.
    };
}
Community
  • 1
  • 1
Mike Zboray
  • 39,828
  • 3
  • 90
  • 122
  • I like the idea of using the list. Using Linq seems kind of expensive? – Peteter May 30 '14 at 08:57
  • @Peteter Expression trees and reflection are more expensive than lambdas, but I doubt it is a significant amount of time. On the order of hundreds of nanoseconds instead of tens. You aren't going to notice that unless you have some pretty strict performance requirements for your tests. – Mike Zboray May 30 '14 at 16:29
  • Thanks! You're probably right. (Performance is always important - I care about the battery life of my user's laptops. I've removed the reference to testing :-) Still, even for testing I care about performance.) – Peteter May 31 '14 at 21:21