RGC RGC - 23 days ago 5
C# Question

How to UnitTest Custom MediaTypeFormatter

public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContent content, TransportContext transportContext)
{
//go lookup the concrete for the interface
var newType = GetNewType(type);
var newValue = GetNewValue(value, type);

var serializer = new XmlSerializer(newType);
return Task.Factory.StartNew(() =>
{
using (var streamWriter = new StreamWriter(stream, _encoder))
{
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
serializer.Serialize(streamWriter, newValue, ns);
}
});
}


This Custom mediatypeformatter is trying to serialize the the namespaces of the xml. Im trying to test this method but throws an error with Cannot access a closed Stream. Is there a way to unit test this method.

Answer

Create an abstraction of the serializer

public interface ISerializer
{
    void Serialize(StreamWriter writer, object value, XmlSerializerNamespaces ns);
}

Then inject an ISerializer to the WriteToStreamAsync method. This enables you to pass a dummy implementation.

public override Task WriteToStreamAsync(ISerializer serializer, Type type, object value, Stream stream, HttpContent content, TransportContext transportContext)
{
    var newType = GetNewType(type);
    var newValue = GetNewValue(value, type);
    return Task.Factory.StartNew(() => {
        using (var streamWriter = new StreamWriter(stream, _encoder)) {
            var ns = new XmlSerializerNamespaces();
            ns.Add("", "");
            serializer.Serialize(streamWriter, newValue, ns);
        }
    });
}

A possible implementation:

public class MyXmlSerializer<T> : ISerializer
{
    private readonly XmlSerializer _xmlSerializer = new XmlSerializer(typeof(T));

    public void Serialize(StreamWriter writer, object value, XmlSerializerNamespaces ns)
    {
        _xmlSerializer.Serialize(writer, value, ns);
    }
}

Possible dummy:

public class DummySerializer : ISerializer
{
    // You can test these properties in the unit test after the call;
    public StreamWriter Writer { get; private set; }
    public object Value { get; private set; }
    public XmlSerializerNamespaces NS { get; private set; }
    public int Calls { get; private set; }

    public void Serialize(StreamWriter writer, object value, XmlSerializerNamespaces ns)
    {
        Writer = writer;
        Value = value;
        NS = ns;
        Calls++;
    }
}

Or use NSubstitute or another mocking framework. Note: these frameworks automatically create dummy implementations of interfaces at runtime.

Programming against interfaces instead of concrete classes not only adds flexibility to your code, but is often mandatory for unit testing.