ILoggable

A place to keep my thoughts on programming

August 21, 2009 .net , ,

Using TDD to learn new code

When I pick up a new framework or library, there’s usually that learning curve where I get familiar with its API, find what works, what doesn’t work, etc. One habit I’ve gotten into is that I create a TestFixture for everything i think i should be able to do and build a test for that assumption. The purpose of these tests is both to make sure the code does what I expect it to, but also to serve as a record of what I’ve already learned. If i later on wonder how some call would function, i first check my test signatures, to see if i’ve already tested that behavior. If there is an appropriate test, I immediately know what the behavior will be, plus i now have working sample code or how to do it.

For example, I was playing around with setting up Moq‘s through Autofac and wanted to come up with a registration that would give me a container scoped Moq object that i could set up before executing a particular test. The resulting test looked like this:

public interface IMockWithAccessor
{
 IMockAccessorValue Accessor { get; }
}
public interface IMockAccessorValue
{
 string Foo { get; }
}

[Test]
public void Create_nested_mock_so_it_can_be_altered_in_container_scope()
{
 var builder = new ContainerBuilder();
 builder.Register(c => new Mock<IMockAccessorValue>())
  .As<Mock<IMockAccessorValue>>().ContainerScoped();
 builder.Register(c => c.Resolve<Mock<IMockAccessorValue>>().Object)
  .As<IMockAccessorValue>().ContainerScoped();
 builder.Register(c =>
 {
  var mockBuilder = new Mock<IMockWithAccessor>();
  mockBuilder.Setup(x => x.Accessor)
                       .Returns(c.Resolve<IMockAccessorValue>());
  return mockBuilder.Object;
 }).As<IMockWithAccessor>().ContainerScoped();

 using (var container = builder.Build().CreateInnerContainer())
 {
  var mockAccessorBuilder = container
                     .Resolve<Mock<IMockAccessorValue>>();
  mockAccessorBuilder.Setup(x => x.Foo).Returns("bar");
  Assert.AreEqual("bar", container
                     .Resolve<IMockWithAccessor>().Accessor.Foo);
 }
}

Sometimes, of course, my expectations are not met and the code does not allow me to do what i set out to do. These test are even more valuable for future reference, as long as i make sure to rename the test to reflect the failed expectation, and alter the asserts to reflect the actual behavior.

I was trying to figure out parametrized component registrations in Autofac. The example showed it being used with FactoryScope. I wondered whether, in default (Singleton) scope, Autofac would use the parameters to create singletons per parameter set. My original test was named Parametrized_resolve_creates_different_singleton_per_parameter_Value. Well, it turned out that, no, autofac does not vary singletons, and parametrized registrations only make sense in FactoryScope. The final test looks like this:

public class ParametrizedSingleton { }
[Test]
public void Parametrized_resolve_without_factory_scope_is_always_a_singleton()
{
 var builder = new ContainerBuilder();
 builder.Register((c, p) => new ParametrizedSingleton());
 using (var container = builder.Build())
 {
  var foo1 = container.Resolve<ParametrizedSingleton>(
                     new NamedParameter("type", "foo"));
  var foo2 = container.Resolve<ParametrizedSingleton>(
                     new NamedParameter("type", "foo"));
  var bar1 = container.Resolve<ParametrizedSingleton>(
                     new NamedParameter("type", "bar"));
  Assert.AreSame(foo1, foo2);
  Assert.AreSame(foo1, bar1);
 }
}

I usually keep these test fixtures in a separate test project in my solution as permanent reference, as i continue to develop the main code. It’s proven useful a number of times when coming back to some old code and having to reacquaint myself with a third party bit of code.

Leave a comment