Testing the lifecycle of components

When using an IoC container I like to have confidence that I can retrieve the components that I think I can (rather than getting an unpleasant surprise at runtime!).

This generally involves bootstrapping the container and writing (integration) tests that resolve the types I need. You won’t generally need a test for every class, as retrieving a root object will fail if any of its dependencies cannot be resolved.

While this is a good start, it’s also useful to test the lifecycle of registered components. For example, you want to ensure that your SessionFactory is a singleton. This calls for some helper assertions! (The examples below are tailored for StructureMap, other containers are available :)

using NUnit.Framework;

namespace Your.Namespace.Here
{
	public class TestingComponentLifecycles
	{
		private IContainer container;

		[TestFixtureSetUp]
		public void FixtureSetUp()
		{
			container = BootstrapContainer();
		}

		[Test]
		public void SessionFactory()
		{
			AssertSingleton<SessionFactory>();
		}

		[Test]
		public void Frobulator()
		{
			AssertTransient<Frobulator>();
		}

		private void AssertSingleton<T>()
		{
			var instance1 = container.Resolve<T>();
			var instance2 = container.Resolve<T>();
			Assert.That(instance1, Is.SameAs(instance2));
		}

		private void AssertTransient<T>()
		{
			var instance1 = container.Resolve<T>();
			var instance2 = container.Resolve<T>();
			Assert.That(instance1, Is.Not.SameAs(instance2));
		}
	}
}

Caching API

Caching, like other utility code, can often clutter your nice clean methods. So why not tuck it away behind a user friendly API? With bonus points for a “fluent interface” :)

using System;

namespace Your.Namespace.Here
{
	public interface ICache
	{
		ICacheLifespan<T> Cache<T>(Func<T> factory);
	}

	public interface ICacheLifespan<T>
	{
		ICacheKeying<T> For(TimeSpan timeToLive);
	}

	public interface ICacheKeying<T>
	{
		T WithKey(string cacheKey);
	}

    public class InMemoryCache : ICache
	{
		private readonly ObjectCache _cache;

		public InMemoryCache(ObjectCache cache)
		{
			_cache = cache;
		}

		public ICacheLifespan<T> Cache<T>(Func<T> factory)
		{
			return new CacheLifespan<T>((ttl, k) =>
			{
				if (_cache.Contains(k))
					return (T)_cache[k];

				var value = factory();

				var cacheItemPolicy = new CacheItemPolicy
				{
					AbsoluteExpiration = DateTimeOffset.Now.Add(ttl)
				};
				_cache.Add(k, value, cacheItemPolicy);

				return value;
			});
		}
	}

	public class CacheLifespan<T> : ICacheLifespan<T>
	{
		private readonly Func<TimeSpan, string, T> _factory;

		public CacheLifespan(Func<TimeSpan, string, T> factory)
		{
			_factory = factory;
		}

		public ICacheKeying<T> For(TimeSpan timeToLive)
		{
			return new CacheKeying<T>(timeToLive, _factory);
		}
	}

	public class CacheKeying<T> : ICacheKeying<T>
	{
		private readonly TimeSpan _timeToLive;
		private readonly Func<TimeSpan, string, T> _factory;

		public CacheKeying(TimeSpan timeToLive, Func<TimeSpan, string, T> factory)
		{
			_timeToLive = timeToLive;
			_factory = factory;
		}

		public T WithKey(string cacheKey)
		{
			return _factory(_timeToLive, cacheKey);
		}
	}

	public class Examples
	{
		private readonly InMemoryCache inMemoryCache = new InMemoryCache(new ObjectCache());

		[Test]
		public void Fluent_caching()
		{
			inMemoryCache.Cache(() => CreateExpensiveObject())
				.For(TimeSpan.FromHours(1))
				.WithKey("cacheKey");
		}
	}
}

Using log4net with OpenRasta

OpenRasta comes with a built in TraceLogger, but if you use log4net in your code then it’s easier to have all your log output going to the same destination. Thanks to ORs excellent pluggable architecture, it’s easy to supply your own implementation of ILogger:

using System;
using log4net;
using OpenRasta;
using OpenRasta.Diagnostics;

namespace Your.Namespace.Here
{
	public class Log4NetLogger : ILogger
	{
		private readonly ILog _log;

		public Log4NetLogger(ILog log)
		{
			_log = log;
		}

		public IDisposable Operation(object source, string name)
		{
			_log.DebugFormat("Entering {0}: {1}", source.GetType().Name, name);
			return new OperationCookie(_log, source);
		}

		public void WriteDebug(string message, params object[] format)
		{
			_log.DebugFormat(message, format);
		}

		public void WriteWarning(string message, params object[] format)
		{
			_log.WarnFormat(message, format);
		}

		public void WriteError(string message, params object[] format)
		{
			_log.ErrorFormat(message, format);
		}

		public void WriteInfo(string message, params object[] format)
		{
			_log.InfoFormat(message, format);
		}

		public void WriteException(Exception e)
		{
			_log.Error("Exception", e);
		}

		private class OperationCookie : IDisposable
		{
			private readonly ILog _log;
			private readonly object _source;

			public OperationCookie(ILog log, object source)
			{
				_log = log;
				_source = source;
			}

			public void Dispose()
			{
				_log.DebugFormat("Exiting {0}".With(_source.GetType().Name));
			}
		}
	}

	public class Log4NetLogger<T> : Log4NetLogger, ILogger<T> where T : ILogSource
	{
		public Log4NetLogger() : base(LogManager.GetLogger(LogSource<T>.Category)) { }
	}
}

This then needs to be supplied to the dependency resolver, for ILogger & ILogger<T> along with an ILog.

Stop… system time!

Writing tests for code that deals with time is always tricky, and Ayende’s solution is probably the most elegant around. There’s always room for some syntactic sugar though!

using System;
using NUnit.Framework;

namespace Your.Namespace.Here
{
	public class SystemTime : IDisposable
	{
		private static readonly Func<DateTime> GetDateTimeNow = () => DateTime.Now;
		private static readonly Func<DateTime> GetUtcNow = () => DateTime.UtcNow;

		public static Func<DateTime> Now = GetDateTimeNow;
		public static Func<DateTime> UtcNow = GetUtcNow;

		public static void Reset()
		{
			Now = GetDateTimeNow;
			UtcNow = GetUtcNow;
		}

		private SystemTime(DateTime now)
		{
			Now = () => now;
		}

		public void Dispose()
		{
			Reset();
		}

		public static SystemTime Is(DateTime dateTime)
		{
			return new SystemTime(dateTime);
		}
	}

	public class Examples
	{
		[Test]
		public void Change_time()
		{
			var bohemiaAdoptsTheGregorianCalendar  = new DateTime(1584, 1, 17);
			using(SystemTime.Is(bohemiaAdoptsTheGregorianCalendar))
			{
				Assert.That(SystemTime.Now(), Is.EqualTo(bohemiaAdoptsTheGregorianCalendar));
				// do something
			}
			Assert.That(SystemTime.Now(), Is.EqualTo(DateTime.Now));
		}
	}
}

And yes, I do like using dates from history :)

External Annotations for ReSharper

Most ReSharper information comes from code inspection and analysis, but not all details can be inferred from the source code alone. For example, code called by reflection (e.g. Activator.CreateInstance) looks like dead code to static analysis. R# offers a solution in the form of External Annotations, XML files supplying extra information.

If you use a test framework other than NUnit, e.g. MbUnit, you may find that your tests are marked as unused by R# even though they can be run. This can fixed by supplying some annotations, the XML needs to go in “%SystemDrive%\Program Files\JetBrains\ReSharper\[Build#]\Bin\ExternalAnnotations\[DllName]\[DllName].xml”. So for MbUnit, it would be ExternalAnnotations\MbUnit\MbUnit.xml. The file needs a list of types, associated with the appropriate R# attribute. The MeansImplicitUseAttribute:

<assembly name="MbUnit">
  <member name="T:MbUnit.Framework.TestAttribute">
    <attribute ctor="M:JetBrains.Annotations.MeansImplicitUseAttribute.#ctor" />
  </member>

states that any code tagged with the TestAttribute will not be considered unused. Other useful attributes are the AssertionMethodAttribute:

  <member name="M:MbUnit.Framework.Assert.IsNotNull(System.Object)">
    <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/>
    <parameter name="anObject">
      <attribute ctor="M:JetBrains.Annotations.AssertionConditionAttribute.#ctor(JetBrains.Annotations.AssertionConditionType)">
        <argument>3</argument>
      </attribute>
    </parameter>
  </member>

the TerminatesProgramAttribute:

  <member name="M:MbUnit.Framework.Assert.Fail">
    <attribute ctor="M:JetBrains.Annotations.TerminatesProgramAttribute.#ctor"/>
  </member>

and the NotNullAttribute. An external annotation file is shipped with the more recent versions of MbUnit.

Best error message ever?

Most error messages are cryptic at best, so coming across this pearl from Castle Windsor was a breath of fresh air!


System.Exception: Looks like you forgot to register the http module Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule Add '<add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor" />' to the <httpModules> section on your web.config. If you're running IIS7 in Integrated Mode you will need to add it to <modules> section under <system.webServer> at Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleManager.Resolve(CreationContext context)

Not only does it tell you what is wrong, but also how to fix it. Kudos to the Castle team.

UPDATE: Now with even more detail!