Il mio dominio è costituito da molte semplici classi 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 attualmente scrivo unit test per ciascuna di queste classi per verificare che la convalida degli argomenti funzioni correttamente e che tutte le proprietà siano inizializzate. Sembra un lavoro estremamente noioso con vantaggi incommensurabili.
La vera soluzione sarebbe per C # supportare nativamente l'immutabilità e i tipi di riferimento non annullabili. 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 ognuna di esse?
Ecco quello che ho ora basato sulle risposte.
Potrei semplificare i controlli null e l'inizializzazione della proprietà in questo modo:
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 di 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 il 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();
Utilizzando 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());
}