How to initialize mail.dll exceptions

A colleague of mine wrote a good article about how frustrating it is to use a third-party library that you can’t easily setup unit tests. TL;DR – You can’t throw exceptions in your unit tests if the constructors are internal. Luckily I’ve found a way to accomplish that.

You see, mail.dll exceptions implement a protected constructor from the base Exception to be serializable. In this post I’ll show you how to initialize a mail.dll exception (or an exception that only has the serializable constructor)

[Serializable]
public class SmtpResponseException : ServerException
{
	protected SmtpResponseException(SerializationInfo info, StreamingContext context)
		: base(info, context)
	{
	}
}

You see, the base Exception class can initialize its subclass based on this protected constructor. If you take a look at what’s under the hood, it looks something like this:

protected Exception(SerializationInfo info, StreamingContext context)
{
  if (info == null)
    throw new ArgumentNullException("info");
  this._className = info.GetString("ClassName");
  this._message = info.GetString("Message");
  ...
}

So you would need to know exactly what dictionary key is used in order to work this constructor. Luckily, I’ve already done the heavy lifting so all you need to do is make a copy of the following class and voila!

/// <summary>
///    Nasty hacky class to create a new instance of SmtpResponseException.
/// </summary>
public class TestSmtpResponseException : SmtpResponseException
{
	protected TestSmtpResponseException(SerializationInfo info, StreamingContext context) : base(info, context) {}

	public static TestSmtpResponseException Create()
	{
		var info = new SerializationInfo(typeof (TestSmtpResponseException), new FormatterConverter());
		info.AddValue("ClassName", "foo");
		info.AddValue("Message", "bar");
		info.AddValue("InnerException", null);
		info.AddValue("HelpURL", null);
		info.AddValue("StackTraceString", null);
		info.AddValue("RemoteStackTraceString", null);
		info.AddValue("RemoteStackIndex", 0);
		info.AddValue("ExceptionMethod", null);
		info.AddValue("HResult", 1); // important, can't be 0
		info.AddValue("Source", null);
		return new TestSmtpResponseException(info, new StreamingContext(StreamingContextStates.Other)); // StreamingContextStates doesn't matter
	}
}

Now you can create an instance of the crazy i-wont-let-you-test-my-code mail.dll SmtpResponseException

var exception = TestSmtpResponseException.Create();

You can grab the full version of this code through my github

Happy unit testing!

This entry was posted in Programming and tagged , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *


*