Il mio dominio è costituito da molte classi semplici e immutabili come questa:
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;
}
}
Scrivere i controlli null e l'inizializzazione delle proprietà sta già diventando molto noioso, ma al momento scrivo unit test per ciascuna di queste classi per verificare che la convalida degli argomenti funzioni correttamente e che tutte le proprietà siano inizializzate. Questo sembra un lavoro estremamente noioso con un vantaggio incommensurabile.
La vera soluzione sarebbe per C # supportare i tipi di riferimento immutabilità e non annullabili in modo nativo. Ma cosa posso fare per migliorare la situazione nel frattempo? Vale la pena scrivere tutti questi test? Sarebbe una buona idea scrivere un generatore di codice per tali classi per evitare di scrivere test per ognuno di essi?
Ecco cosa ho ora basato sulle risposte.
Potrei semplificare i controlli nulli e l'inizializzazione delle proprietà per assomigliare a questo:
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));
Utilizzando la seguente implementazione da 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;
}
}
Testare i controlli null è facile usando GuardClauseAssertion
da AutoFixture.Idioms
(grazie per il suggerimento, Esben Skov Pedersen ):
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var assertion = new GuardClauseAssertion(fixture);
assertion.Verify(typeof(Address).GetConstructors());
Questo potrebbe essere ulteriormente compresso:
typeof(Address).ShouldNotAcceptNullConstructorArguments();
Utilizzo di questo metodo di estensione:
public static void ShouldNotAcceptNullConstructorArguments(this Type type)
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var assertion = new GuardClauseAssertion(fixture);
assertion.Verify(type.GetConstructors());
}