Meine Domain besteht aus vielen einfachen unveränderlichen Klassen wie dieser:
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;
}
}
Das Schreiben der Nullprüfungen und der Eigenschaftsinitialisierung wird bereits sehr mühsam. Derzeit schreibe ich Unit-Tests für jede dieser Klassen, um zu überprüfen, ob die Argumentvalidierung ordnungsgemäß funktioniert und alle Eigenschaften initialisiert wurden. Das fühlt sich nach extrem langweiliger Arbeit mit unangemessenem Nutzen an.
Die eigentliche Lösung wäre, dass C # Unveränderlichkeit und nicht nullbare Referenztypen nativ unterstützt. Aber was kann ich in der Zwischenzeit tun, um die Situation zu verbessern? Lohnt es sich, all diese Tests zu schreiben? Wäre es eine gute Idee, einen Codegenerator für solche Klassen zu schreiben, um zu vermeiden, dass Tests für jede einzelne geschrieben werden?
Hier ist, was ich jetzt basierend auf den Antworten habe.
Ich könnte die Nullprüfungen und die Eigenschaftsinitialisierung so vereinfachen:
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));
Mit der folgenden Implementierung von 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;
}
}
Das Testen der Nullprüfungen ist mit dem GuardClauseAssertion
von einfach AutoFixture.Idioms
(danke für den Vorschlag, Esben Skov Pedersen ):
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var assertion = new GuardClauseAssertion(fixture);
assertion.Verify(typeof(Address).GetConstructors());
Dies könnte noch weiter komprimiert werden:
typeof(Address).ShouldNotAcceptNullConstructorArguments();
Mit dieser Erweiterungsmethode:
public static void ShouldNotAcceptNullConstructorArguments(this Type type)
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var assertion = new GuardClauseAssertion(fixture);
assertion.Verify(type.GetConstructors());
}