I have a bunch of exceptions which follow the same schema: I have a parameter that is given into a text like this:
public class ContainerCouldNotStartedException : Exception
{
private static readonly string Text = "Container could not be started: {0}. Please see docker logging for more information";
public ContainerCouldNotStartedException()
{
}
public ContainerCouldNotStartedException(string name)
: base(String.Format(Text, name))
{
}
}
Now I want to test this.
To avoid 10 copied test for 10 exceptions my idea is to test it generic like this:
public static void Test_String_Is_In_Message(Type type, string name)
{
ConstructorInfo ctor = type.GetConstructor(new[] { typeof(string) });
dynamic exception = ctor.Invoke(new object[] { name });
Assert.That(exception.Message, Does.Contain(name));
}
And call it like this:
[Test]
[TestCase("HarryPotter")]
[TestCase("HermineGranger")]
[TestCase("LuciusMalfoy")]
public void Message_Has_Name(string name)
{
ExceptionTest.Test_String_Is_In_Message(typeof(ContainerCouldNotStartedException), name);
ExceptionTest.Test_String_Is_In_Message(typeof(DatabaseNameNotCorrectException), name);
ExceptionTest.Test_String_Is_In_Message(typeof(DatabaseNotCorrectException), name);
ExceptionTest.Test_String_Is_In_Message(typeof(DatabaseVersionNotReadableException), name);
ExceptionTest.Test_String_Is_In_Message(typeof(VersionNotFoundException), name);
}
That works very fine and all tests are green.
Now one single exception has a GUID parameter, instead of a string.
So instead of having my method Test_String_Is_In_Message
copied to times, I made it generic:
public static void Test_String_Is_In_Message<T>(Type type, T name)
{
ConstructorInfo ctor = type.GetConstructor(new[] { typeof(T) });
dynamic exception = ctor.Invoke(new object[] { name });
Assert.That(exception.Message, Does.Contain(name));
}
Now all tests fail.
When I debug the test it is all fine for me, I can see the name in the message, but the assert still fails. Why?
The usage of dynamic
kind of obfuscated the problem. The problem is that Does.Contain()
expects a string
according to the docs. So changing your helper method to the following made all the tests pass for me:
public static void Test_String_Is_In_Message<T>(Type type, T name)
{
ConstructorInfo ctor = type.GetConstructor(new[] { typeof(T) });
try
{
ctor.Invoke(new object[] { name });
}
catch (Exception e)
{
Assert.That(e.Message, Does.Contain(name.ToString()));
}
}