Moja domena składa się z wielu prostych niezmiennych klas takich jak to:
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;
}
}
Pisanie kontroli zerowej i inicjowanie właściwości jest już bardzo uciążliwe, ale obecnie piszę testy jednostkowe dla każdej z tych klas, aby sprawdzić, czy sprawdzanie poprawności argumentów działa poprawnie i czy wszystkie właściwości zostały zainicjowane. Wydaje się, że praca jest wyjątkowo nudna i przynosi niewspółmierne korzyści.
Prawdziwym rozwiązaniem byłoby, aby język C # obsługiwał niezmienność i typy zerowalne. Ale co mogę w międzyczasie poprawić? Czy warto pisać wszystkie te testy? Czy dobrym pomysłem byłoby napisanie generatora kodu dla takich klas, aby uniknąć pisania testów dla każdej z nich?
Oto, co mam teraz na podstawie odpowiedzi.
Mogę uprościć sprawdzanie wartości zerowej i inicjowanie właściwości, aby wyglądały następująco:
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));
Za pomocą następującej implementacji Roberta Harveya :
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;
}
}
Testowanie czeków zerowych jest łatwe przy użyciu narzędzia GuardClauseAssertion
from AutoFixture.Idioms
(dzięki za sugestię, Esben Skov Pedersen ):
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var assertion = new GuardClauseAssertion(fixture);
assertion.Verify(typeof(Address).GetConstructors());
Można to jeszcze bardziej skompresować:
typeof(Address).ShouldNotAcceptNullConstructorArguments();
Za pomocą tej metody rozszerzenia:
public static void ShouldNotAcceptNullConstructorArguments(this Type type)
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var assertion = new GuardClauseAssertion(fixture);
assertion.Verify(type.GetConstructors());
}