Mi dominio consta de muchas clases simples inmutables como esta:
public class Person
{
public string FullName { get; }
public string NameAtBirth { get; }
public string TaxId { get; }
public PhoneNumber PhoneNumber { get; }
public Address Address { get; }
public Person(
string fullName,
string nameAtBirth,
string taxId,
PhoneNumber phoneNumber,
Address address)
{
if (fullName == null)
throw new ArgumentNullException(nameof(fullName));
if (nameAtBirth == null)
throw new ArgumentNullException(nameof(nameAtBirth));
if (taxId == null)
throw new ArgumentNullException(nameof(taxId));
if (phoneNumber == null)
throw new ArgumentNullException(nameof(phoneNumber));
if (address == null)
throw new ArgumentNullException(nameof(address));
FullName = fullName;
NameAtBirth = nameAtBirth;
TaxId = taxId;
PhoneNumber = phoneNumber;
Address = address;
}
}
Escribir las verificaciones nulas y la inicialización de propiedades ya se está volviendo muy tedioso, pero actualmente escribo pruebas unitarias para cada una de estas clases para verificar que la validación de argumentos funciona correctamente y que todas las propiedades se inicializan. Esto se siente como un trabajo extremadamente aburrido con beneficios inconmensurables.
La solución real sería que C # admitiera inmutabilidad y tipos de referencia no anulables de forma nativa. Pero, ¿qué puedo hacer para mejorar la situación mientras tanto? ¿Vale la pena escribir todas estas pruebas? ¿Sería una buena idea escribir un generador de código para tales clases para evitar escribir pruebas para cada una de ellas?
Esto es lo que tengo ahora basado en las respuestas.
Podría simplificar las verificaciones nulas y la inicialización de propiedades para que se vea así:
FullName = fullName.ThrowIfNull(nameof(fullName));
NameAtBirth = nameAtBirth.ThrowIfNull(nameof(nameAtBirth));
TaxId = taxId.ThrowIfNull(nameof(taxId));
PhoneNumber = phoneNumber.ThrowIfNull(nameof(phoneNumber));
Address = address.ThrowIfNull(nameof(address));
Usando la siguiente implementación de Robert Harvey :
public static class ArgumentValidationExtensions
{
public static T ThrowIfNull<T>(this T o, string paramName) where T : class
{
if (o == null)
throw new ArgumentNullException(paramName);
return o;
}
}
Probar las comprobaciones nulas es fácil usando GuardClauseAssertionfrom AutoFixture.Idioms(gracias por la sugerencia, Esben Skov Pedersen ):
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var assertion = new GuardClauseAssertion(fixture);
assertion.Verify(typeof(Address).GetConstructors());
Esto podría comprimirse aún más:
typeof(Address).ShouldNotAcceptNullConstructorArguments();
Usando este método de extensión:
public static void ShouldNotAcceptNullConstructorArguments(this Type type)
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var assertion = new GuardClauseAssertion(fixture);
assertion.Verify(type.GetConstructors());
}