Friday, 18 April 2014

Calling generic methods with runtime Type parameters

In the normal course of events, a call to a generic method needs to have its type resolved at compile time. For example, consider this class and method:
class TypeWriter
{
    public void WriteType<T>(TextWriter target)
    {
        target.WriteLine("T is {0}"typeof(T));
    }
}
This generic method needs to be called with its type parameter resolved at runtime, like this:
var typeWriter = new TypeWriter();
typeWriter.WriteType<Program>(Console.Out);
which gives this output:


But what do you do if you only discover the types at runtime so don't know the types at compile time? This commented code wouldn't compile because the variable assemblyType can't be resolved to a generic parameter:
foreach (var assemblyType in Assembly.GetExecutingAssembly().GetTypes())
{
    // typeWriter.WriteType<assemblyType>(Console.Out);
}

This is where System.Reflection comes in. The MethodInfo class has a method MakeGenericMethod that takes an array of System.Type, substitutes the method's generic parameters for the arguments and returns a new MethodInfo instance. This new MethodInfo instance can then be invoked like any other. Here's how this looks in code:
foreach (var assemblyType in Assembly.GetExecutingAssembly().GetTypes())
{
    // Get a handle on the method to call
    var method = typeof(TypeWriter).GetMethod("WriteType");

    // Pass the type parameter(s)
    var genericMethod = method.MakeGenericMethod(assemblyType);

    // Call the method on the TypeWriter instance, passing parameter(s)
    genericMethod.Invoke(typeWriter, new[] { Console.Out });
}
This gives the output:


Thursday, 3 April 2014

KeyedCollection

During a talk at DevWeek 2014 I discovered the KeyedCollection<TKey,TItem> class. The class is in the System.Collections.ObjectModel namespace, and is an alternative to the Dictionary<TKey,TValue> for items where the key is embedded in the item itself. The following code sample shows where it pays dividends to use a KeyedCollection over a Dictionary.

The following program creates a dictionary of Person objects; it uses the Id of the Person as the key, and the person itself as the value:


Bearing in mind that this is a contrived example, there is a problem with this code; having to specify the key manually has lead to a typo (didn't you spot it?):


If the key to use for your collection item can be derived from the value, the KeyedCollection allows you to do that.
The KeyedCollection class is abstract, so you need to inherit from it. Having done so, you can override the GetKeyForItem method; this is the method that the framework calls to obtain the key of the item:


Items can then be added to the collection as you would any collection, either using the Add method, or an object initialiser as I've done here:


When retrieving an item, the KeyedCollection behaves like a Dictionary rather than a List, because you access items by their key rather that their position in the collection:


See more about the KeyedCollection class on MSDN: http://msdn.microsoft.com/en-us/library/ms132438(v=vs.110).aspx

System.BitConverter Class

Every now and again a new framework class comes to my attention. At DevWeek I was attending a talk on Cryptography and an incidental part of the talk featured the BitConverter class. This is a class in the System namespace and has a bunch of static methods that convert to and from a byte array.

The ToString(byte[]) method was the one that I saw being used. It takes an array of bytes and converts each byte to its 2 character hexadecimal equivalent. This is an alternative to Base64 encoding and is arguably more human-friendly.




Other methods on the BitConverter class allow you to convert between a byte array and numerical types:

For more details, see the MSDN documentation at http://msdn.microsoft.com/en-us/library/system.bitconverter(v=vs.110).aspx

Thursday, 31 October 2013

Faking AppSettings in tests

If you have some code that uses configuration from an app.config or web.config file, and you need to retrospectively write tests for it, there are several approaches you can take to get fake setting into your tests.

Given this code
using System;
using System.Configuration;
using System.IO;

namespace Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var writer = new StringWriter())
            {
                new SeasonWriter().WriteSeason(writer);
                Console.WriteLine(writer);
                Console.ReadLine();
            }
        }
    }

    public class SeasonWriter
    {
        public void WriteSeason(TextWriter textWriter)
        {
            var month = ConfigurationManager.AppSettings["Month"];
            switch (month)
            {
                case "January":
                case "February":
                case "December":
                    textWriter.Write("Winter");
                    break;
                case "March":
                case "April":
                case "May":
                    textWriter.Write("Spring");
                    break;
                case "June":
                case "July":
                case "August":
                    textWriter.Write("Summer");
                    break;
                case "September":
                case "October":
                case "November":
                    textWriter.Write("Autumn");
                    break;
                default:
                    throw new ConfigurationErrorsException("No setting defined for 'Month'."
                        + Environment.NewLine
                        + "Please add a setting to the .exe.config file under the section AppSettings."
                        + Environment.NewLine
                        + "For more info on the .exe.config file, follow this link "
                        + "http://msdn.microsoft.com/en-us/library/vstudio/1fk1t1t0(v=vs.110).aspx");
            }
        }
    }
}
In order to get tests around the SeasonWriter class, the AppSettings entry "Month" needs to be faked or abstracted. Some options are:

Create an app.config file in the test project

This is the most obvious starting point. Create a test project to contain the SeasonWriterTests file, with an app.config containing a "Month" entry:
<appSettings>
  <add key="Month" value="January"/>
</appSettings>
using NUnit.Framework;
using System.IO;

namespace Demo.Test
{
    [TestFixture]
    public class SeasonWriterTests
    {
        [Test]
        public void WriteSeasonExpectWinter()
        {
            var writer = new StringWriter();
            var target = new SeasonWriter();
            target.WriteSeason(writer);
            Assert.That(writer.ToString(), Is.EqualTo("Winter"));
        }
    }
}
This will allow the test to run, but will limit you to testing a single path through the code. It's also flaky, because your test depends on a magic string in a separate file.

Pass the configuration setting in


This solution is a refactor of the WriteSeason method, so it takes the config setting in as a string. This sounds like a clean fix, with benefits
  • the responsibility for getting that value has been handed off to the user of the method
  • the code is easier to test

However, there are downsides
  • the refactor is an untested change
  • there could be many users of this method, and each one would be responsible for getting the month value
  • the exception type in the WriteSeason method is no longer correct

Set the config value


The easiest way to fake an AppSettings value is just to set it in your test class. ConfigurationManager.AppSettings is just a NameValueCollection, and items can be written as well as read:
using NUnit.Framework;
using System.IO;
using System.Configuration;

namespace Demo.Test
{
    [TestFixture]
    public class SeasonWriterTests
    {
        [TestCase("January""Winter")]
        [TestCase("February""Winter")]
        [TestCase("March""Spring")]
        [TestCase("April""Spring")]
        [TestCase("May""Spring")]
        [TestCase("June""Summer")]
        [TestCase("July""Summer")]
        [TestCase("August""Summer")]
        [TestCase("September""Autumn")]
        [TestCase("October""Autumn")]
        [TestCase("November""Autumn")]
        [TestCase("December""Winter")]
        public void WriteSeasonExpectCorrectSeasonForMonth(string month, string expectedSeason)
        {

          ConfigurationManager.AppSettings["Month"] = month;

            var writer = new StringWriter();
            var target = new SeasonWriter();
            target.WriteSeason(writer);
            Assert.That(writer.ToString(), Is.EqualTo(expectedSeason));
        }
    }
}

Friday, 25 October 2013

Disposable HtmlHelper Extensions

If you're regularly using a block of HTML elements consisting of opening tags and closing tags, you might want to employ the using pattern used by the framework's FormExtensions:


This is pretty straightforward; you need to create a class that implements IDisposable and render the opening tags in the constructor, and the closing tags in the Dispose method.

As an example I'll implement an HtmlHelper extension that renders a multi-column table with a header row containing the column titles specified, that will be rendered like this:


The first step is to create a static class for the extension method, and the extension method itself. This should be an extension method for the HtmlHelper object, and needs to return an instance of a class that implements IDisposable:


The HtmlHelper exposes a ViewContext, which has a Writer property; this is a TextWriter, and it's this object that stores the HTML that will be sent to the HttpResponse. The writer is the object that we need to pass our HTML string to. For this example, I also need the headers to render, so I've added a params parameter to the extension method:


The implementation of the disposable helper constructor builds and writes the table header, and the dispose method writes the closing tag:


The usage of the helper in the view can be changed to this:


Or this:


And gets rendered like this:


The code for the example helper class is available as a GitGist

Saturday, 19 October 2013

Dealing with static methods in unit tests

This is a follow up post to my previous one on adding tests to legacy code, and shows several techniques for removing a dependency on a call to a static method. Once again, I make no apologies for the state of the resulting code; these techniques are each a pragmatic step towards getting legacy code under test so it can be refactored.

The code to test

The class to write tests for is intentionally simple; it has a single method that takes a string which is used to look up a value in a file, and modifies that string before returning it. Because of the dependency on a file, the code doesn't run from a unit test without that file being present.
public class Builder
{
    public string BuildString(string configName)
    {
        var retVal = ConfigReader.GetConfig(configName);
        return "xx" + retVal + "xx";
    }
}
The ConfigReader class also has a single method, that reads a value from a custom configuration file:
public class ConfigReader
{
    public static string GetConfig(string setting)
    {
        using (var reader = File.OpenText("..\app.config"))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                var elements = line.Split('=');
                if (elements[0] == setting)
                {
                    return elements[1];
                }
            }
        }
        return null;
    }
}

Add virtual method

This is the technique that I highlighted in my original post. It involves creating a virtual method in the class under test, which in a production setting will delegate the call to the existing static method. In a test scenario though, it allows the class under test to be subclassed, and override the virtual method to return a dummy result.

Notes

  • This technique can only be used when the class under test is not sealed
  • It requires no changes to the static class

Steps to implement:

Class under test
  1. Add a virtual method
  2. Delegate the call to the static method to the new virtual method
  3. Update calls to the static method to call the new method
public class Builder
{
    public string BuildString(string configName)
    {
        // 3
        var retVal = GetConfig(configName);
        return "xx" + retVal + "xx";
    }

    // 1
    protected virtual string GetConfig(string configName)
    {
        // 2
        return ConfigReader.GetConfig(configName);
    }
}
Test class
  1. Create a subclass of the class under test
  2. Override the virtual method to return a known result
  3. Create an instance of the subclass as the test target
[TestFixture]
public class BuilderTests
{
    [Test]
    public void BuildString()
    {
        // 3
        var target = new FakeBuilder();
        Assert.That(target.BuildString(""), Is.EqualTo("xxExpectedxx"));
    }

    // 1
    private class FakeBuilder : Builder
    {
        // 2
        protected override string GetConfig(string configName)
        {
            return "Expected";
        }
    }
}

Delegate to instance method

This technique involves adding an instance method to the dependency class, and extracting its interface. A stub of this interface can then be passed to the class for testing.

Notes

  • This technique can only be used when the dependency class is not marked static

Steps to implement:

Dependency class
  1. Add an instance method
  2. Delegate from the instance method to static method
  3. Extract the interface
  4. Implement the interface
// 3
public interface IConfigReader
{
    string GetConfiguration(string setting);
}

//4
public class ConfigReader : IConfigReader
{
    // 1
    public string GetConfiguration(string setting)
    {
        // 2
        return GetConfig(setting);
    }

    public static string GetConfig(string setting)
    {
        using (var reader = File.OpenText("..\app.config"))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                var elements = line.Split('=');
                if (elements[0] == setting)
                {
                    return elements[1];
                }
            }
        }
        return null;
    }
}
Class under test
  1. Add a new constructor to accept an implementation of the interface
  2. Update existing constructor(s) to create default implementation
  3. Update calls to static method to call interface method
public sealed class Builder
{
    private IConfigReader configReader;

    // 2
    public Builder()
        : this(new ConfigReader())
    { }

    // 1
    internal Builder(IConfigReader ConfigReader)
    {
        this.configReader = ConfigReader;
    }

    public string BuildString(string configName)
    {
        // 3
        var retVal = configReader.GetConfiguration(configName);
        return "xx" + retVal + "xx";
    }
}
Test class
  1. Stub the new interface
  2. Pass the stub to the new constructor
[TestFixture]
public class BuilderTests
{
    [Test]
    public void BuildString()
    {
        // 1
        var configFileReader = MockRepository.GenerateMock<IConfigReader>();
        configFileReader.Stub(fr => fr.GetConfiguration(Arg<string>.Is.Anything))
            .Return("Expected");

        //2
        var target = new Builder(configFileReader);
        Assert.That(target.BuildString(""), Is.EqualTo("xxExpectedxx"));
    }
}

Wrap static class

This technique is to create an instance class that delegates calls to the static class, but allows an interface to be specified for the calling class to use.

Notes

  • This technique does not require any change to the dependency class

Steps to implement:

Wrapper class
  1. Create a new class with an instance method
  2. Delegate from the instance method to the static methods
  3. Extract the interface of the new class
// 3
public interface IConfigReaderWrapper
{
    string GetConfig(string setting);
}

// 1
public class ConfigReaderWrapper : IConfigReaderWrapper
{
    // 2
    public string GetConfig(string setting)
    {
        return ConfigReader.GetConfig(setting);
    }
}
Class under test
  1. Add a new constructor to accept an implementation of the new interface
  2. Update existing constructor(s) to create the default implementation
  3. Change all static method calls to call instance methods on the new interface
public class Builder
{
    private IConfigReaderWrapper configReader;

    // 2
    public Builder()
        : this(new ConfigReaderWrapper())
    { }

    // 1
    internal Builder(IConfigReaderWrapper ConfigReader)
    {
        this.configReader = ConfigReader;
    }

    public string BuildString(string configName)
    {
        // 3
        var retVal = configReader.GetConfig(configName);
        return "xx" + retVal + "xx";
    }
}
Test class
  1. Stub the new interface
  2. Pass to stub to new constructor
[TestFixture]
public class BuilderTests
{
    [Test]
    public void BuildString()
    {
        // 1
        var configFileReader = MockRepository.GenerateMock<IConfigReaderWrapper>();
        configFileReader.Stub(fr => fr.GetConfig(Arg<string>.Is.Anything))
            .Return("Expected");

        // 2
        var target = new Builder(configFileReader);
        Assert.That(target.BuildString(""), Is.EqualTo("xxExpectedxx"));
    }
}

Pass lambda as implementation of static method

This technnique is to use a property on the static class to hold the implementation of the static method, and pass a fake implementation for testing.

Notes

  • Does not need changes to the class under test

Steps to implement:

Static class
  1. Extract the implementation of the static method to a private static method
  2. Add a static property to hold a lambda whose signature matches that of the private method
  3. Add a static constructor
  4. Default the lambda to call the private method
  5. Modify the static method to execute the lambda held in the property
public static class ConfigReader
{
    // 2
    internal static Func<stringstring> getConfigImpl { get; set; }

    // 3
    static ConfigReader()
    {
        // 4
        getConfigImpl = s => _GetConfig(s);
    }

    public static string GetConfig(string setting)
    {
        // 5
        return getConfigImpl(setting);
    }

    // 1
    private static string _GetConfig(string setting)
    {
        using (var reader = File.OpenText("..\app.config"))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                var elements = line.Split('=');
                if (elements[0] == setting)
                {
                    return elements[1];
                }
            }
        }
        return null;
    }
}
Test class
  1. Set the new property on the static class to the fake implementation
[TestFixture]
public class BuilderTests
{
    [Test]
    public void BuildString()
    {
        // 1
        ConfigReader.getConfigImpl = s => "Expected";
        
        var target = new Builder();
        Assert.That(target.BuildString(""), Is.EqualTo("xxExpectedxx"));
    }
}

Any more?

One other technique is to use an advanced mocking framework that can stub static methods; unfortunately none of the free ones I know have this feature.

Can you think of any other techniques that I haven't covered? If so, please leave a comment and let me know.

The code for these examples is on GitHub, click here.