Skip to content

Instantly share code, notes, and snippets.

@aaronhoffman
Last active November 5, 2020 21:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aaronhoffman/1e068fc2be4fab05cf4805841cb3c126 to your computer and use it in GitHub Desktop.
Save aaronhoffman/1e068fc2be4fab05cf4805841cb3c126 to your computer and use it in GitHub Desktop.
Unit Test Constructor ArgumentNullException
// source: https://mikhail.io/2015/04/unit-testing-null-parameter-checks/
public void ConstructorMustThrowArgumentNullException(Type type)
{
foreach (var constructor in type.GetConstructors())
{
var parameters = constructor.GetParameters();
var mocks = parameters.Select(
p =>
{
Type mockType = typeof(Mock<>).MakeGenericType(
new[] { p.ParameterType });
return (Mock)Activator.CreateInstance(mockType);
}).ToArray();
for (int i = 0; i < parameters.Length; i++)
{
var mocksCopy = mocks.Select(m => m.Object).ToArray();
mocksCopy[i] = null;
try
{
constructor.Invoke(mocksCopy);
Assert.Fail("ArgumentNullException expected for parameter {0} of constructor, but no exception was thrown", parameters[i].Name);
}
catch (TargetInvocationException ex)
{
Assert.AreEqual(
typeof(ArgumentNullException),
ex.InnerException.GetType(),
string.Format("ArgumentNullException expected for parameter {0} of constructor, but exception of type {1} was thrown", parameters[i].Name, ex.InnerException.GetType()));
}
}
}
}
public static class ConstructorTestingHelper
{
/// <summary>
/// Uses reflection to find all constructors and all parameters to each constructor.
/// Calls each constructor one time for each parameter, passing a null for each parameter one at a time to verify an ArgumentNullException is thrown.
/// </summary>
/// <param name="type">The type to be tested.</param>
public static void VerifyAllConstructorsThrowArgumentNullExceptionsForEveryParameter(Type type)
{
if (type == null)
{
return;
}
foreach (var constructor in type.GetConstructors())
{
var parameters = constructor.GetParameters();
var mocks = parameters
.Select(p =>
{
var mockType = typeof(Mock<>).MakeGenericType(new[] { p.ParameterType });
return (Mock)Activator.CreateInstance(mockType);
})
.ToArray();
for (int i = 0; i < parameters.Length; i++)
{
var mockInstances = mocks.Select(m => m.Object).ToArray();
mockInstances[i] = null;
try
{
constructor.Invoke(mockInstances);
Assert.Fail($"{nameof(ArgumentNullException)} expected for parameter [{parameters[i].Name}] of [{type.FullName}] constructor, but no exception was thrown.");
}
catch (TargetInvocationException ex)
{
Assert.AreEqual(
typeof(ArgumentNullException),
ex.InnerException.GetType(),
$"{nameof(ArgumentNullException)} expected for parameter [{parameters[i].Name}] of [{type.FullName}] constructor, but exception of type [{ex.InnerException.GetType().FullName}] was thrown.");
}
}
}
}
}
@aaronhoffman
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment