Run R# tests without switching to the mouse

As I do test-driven development, I find it annoying to switch over to the Mouse every time I want to run my tests.

So I just hooked up a hotkey for running unit tests.

CTRL+ALT+T usually shows the Test Session pane – I’ve never used it, so I assigned it to:

ReSharper.UnitTest_ContextRun

Context_Run runs the test method your cursor is inside, or if you move out of the method it will run the whole test fixture.

CTRL+SHIFT+F6 (Switch to previous window pane) then brings the focus back to your code.

kick it on DotNetKicks.com

Advertisements

How to make ASP.net session state testable

In the initial version, the wrapper simply throws an exception if HttpContext.Current or HttpContext.Current.Session is not available.

So in our Test-Methods we have to “mock” out the SessionState somehow. Basically we just need to override the Session State with a static dictionary within the computing Thread.

I would like to write my tests like this…

[Test]
public void TestOverride()
{
  using(SessionVariableStorage.Override(new Dictionary<string, object>()))
  {
    // normally a call to code that uses session variables internally
    var sessionString = new SessionVariable("sessionString"); 
    Assert.IsFalse(sessionString.HasValue);
    sessionString.Value = "Hello, world!";
    Assert.IsTrue(sessionString.HasValue);
    Assert.AreEqual("Hello, world!", sessionString.Value);
  }
}

To enable that, I need an extra static class “SessionVariableStorage” and some modifications in the SessionVariable<T>.

public static class SessionVariableStorage
{
  internal static readonly ThreadVariable<IDictionary<string, object>> Storage =
    new ThreadVariable<IDictionary<string, object>>();

  public static IDisposable Override(IDictionary<string, object> storage)
  {
    return Storage.Use(storage);
  }
}

Every time before I access the HttpSession I have to check wether it’s currently overridden or not. Here is the new version (requiring ThreadVariable<T>)

/// <summary>
/// Wrapper class for <see cref="HttpContext.Session"/>.
/// Author: Lars Corneliussen
/// Source: https://startbigthinksmall.wordpress.com/2008/05/14/how-to-wrap-the-aspnet-session-state/
/// </summary>
/// <typeparam key="T">
/// The type of the value to be stored.
/// </typeparam>
public class SessionVariable<T>
{
  private readonly string key;
  private readonly Func<T> initializer;

  /// <summary>
  /// Initializes a new session variable.
  /// </summary>
  /// <param name="key">
  /// The key to use for storing the value in the session.
  /// </param>
  public SessionVariable(string key)
  {
    if (string.IsNullOrEmpty(key))
      throw new ArgumentNullException("key");

    this.key = GetType() + key;
  }

  /// <summary>
  /// Initializes a new session variable with a initializer.
  /// </summary>
  /// <param name="key">
  /// The key to use for storing the value in the session.
  /// </param>
  /// <param name="initializer">
  /// A function that is called in order to create a 
  /// default value per session.
  /// </param>
  public SessionVariable(string key, Func<T> initializer) : this(key)
  {
    if (initializer == null) 
      throw new ArgumentNullException("initializer");

    this.initializer = initializer;
  }


  private object GetInternalValue(bool initializeIfNessesary)
  {
    if (SessionVariableStorage.Storage.HasCurrent)
    {
      var dictionary = SessionVariableStorage.Storage.Current;

      object value;

      if (!dictionary.TryGetValue(key, out value) && initializeIfNessesary
          && initializer != null)
        dictionary.Add(key, value = initializer());

      return value;
    }
    else
    {
      HttpSessionState session = CurrentSession;

      var value = session[key];

      if (value == null && initializeIfNessesary
          && initializer != null)
        session[key] = value = initializer();

      return value;
    }
  }

  private static HttpSessionState CurrentSession
  {
    get
    {
      var current = HttpContext.Current;

      if (current == null)
        throw new InvalidOperationException(
          "No HttpContext is not available.");

      var session = current.Session;
      if (session == null)
        throw new InvalidOperationException(
          "No Session available on current HttpContext.");
      return session;
    }
  }

  /// <summary>
  /// Indicates wether there is a value present or not.
  /// </summary>
  public bool HasValue
  {
    get { return GetInternalValue(false) != null; }
  }

  /// <summary>
  /// Sets or gets the value in the current session.
  /// </summary>
  /// <exception cref="InvalidOperationException">
  /// If you try to get a value while none is set. 
  /// Use <see cref="ValueOrDefault"/> for safe access.
  /// </exception>
  public T Value
  {
    get
    {
      object v = GetInternalValue(true);

      if (v == null)
        throw new InvalidOperationException(
          "The session does not contain any value for '"
          + key + "'.");

      return (T) v;
    }
    set
    {
      if (SessionVariableStorage.Storage.HasCurrent)
        SessionVariableStorage.Storage.Current.Add(key, value);
      else
        CurrentSession[key] = value;
    }
  }

  /// <summary>
  /// Gets the value in the current session or if 
  /// none is available <c>default(T)</c>.
  /// </summary>
  public T ValueOrDefault
  {
    get
    {
      object v = GetInternalValue(true);

      if (v == null)
        return default(T);

      return (T)v;
    }
  }

  /// <summary>
  /// Clears the value in the current session.
  /// </summary>
  public void Clear()
  {
    if (SessionVariableStorage.Storage.HasCurrent)
      SessionVariableStorage.Storage.Current.Remove(key);
    else
      CurrentSession.Remove(key);
  }
}