Ostatnio natknąłem się na nowo napisany kod, który był przeplatany dużą ilością Debug.Assert (C #).
Czy powinniśmy nadal używać tego na szeroką skalę, pomimo ogólnego stosowania TDD, BDD i testów jednostkowych?
Ostatnio natknąłem się na nowo napisany kod, który był przeplatany dużą ilością Debug.Assert (C #).
Czy powinniśmy nadal używać tego na szeroką skalę, pomimo ogólnego stosowania TDD, BDD i testów jednostkowych?
Odpowiedzi:
Nie widzę powodu, dla którego nie powinieneś używać Assert. Czyniąc to, już uznałeś potrzebę ochrony, takiej jak warunki wstępne i niezmienniki, i robisz krok w kierunku projektowania według umowy . Assert to tylko jeden ze sposobów na osiągnięcie tego ...
// Precondition using Asert
void SomeMethod(Foo someParameter)
{
Debug.Assert(someParameter != null)
}
// Precondition using If-Then-Throw
void SomeMethod(Foo someParameter)
{
if (someParameter == null)
throw new ArgumentNullException("someParameter");
}
// Precondition using Code Contracts
void SomeMethod(Foo someParameter)
{
Contract.Requires(someParameter != null);
}
// Precondition using some custom library
void SomeMethod(Foo someParameter)
{
Require.ArgumentNotNull(() => someParameter);
}
Wszystkie są sposobami na osiągnięcie tego samego: niezawodność kodu. Sprowadza się to tylko do wyboru opcji, z których Assert jest prawidłowym wyborem.
Zauważ, że jak dotąd nie wspominałem o testach jednostkowych, ponieważ osiągają one coś zupełnie innego. Test jednostkowy formalnie potwierdza solidność kodu, wykonując osłonę:
[Test]
void SomeMethod_WhenGivenNull_ThrowsArgumentNullException()
{
delegate call = () => someObject.SomeMethod(null);
Assert.That(call).Throws<ArgumentNullException>();
}
To zupełnie inny rodzaj twierdzeń ...
** Należy pamiętać, że w niektórych środowiskach testowanie jednostkowe pod kątem niepowodzenia asercji jest dość trudne, ponieważ awaria asercji może skrócić cały czas działania, więc jedna z pozostałych opcji może być preferowana ... *
Uważam twierdzenia i testy jednostkowe za dwa różne narzędzia w moim zestawie narzędzi. Niektóre rzeczy lepiej pasują do jednej, a niektóre lepiej do drugiej.
Jako przykład, obecnie używam głównie asercji do sprawdzania poprawności parametrów metod niepublicznych.
W dzisiejszych czasach uważam Debug.Assert za przedwczesną optymalizację. O ile naprawdę nie potrzebujesz wydajności, pomijanie Assert w trybie wydania może dłużej ukrywać błędy.
Jak zauważa MattDavey, kontrakty kodowe mogą być lepsze, zapewniając sprawdzanie statyczne zamiast sprawdzania dynamicznego, a jeśli nie są dostępne, wolę Trace.Assert lub zwykły staryif(x) throw SomeException;
Debug
klasy zostaną pominięte podczas kompilacji ... więc tłumienie wywołań w celu zwiększenia Assert
wydajności nie jest tylko przedwczesną optymalizacją, to zwykły nonsens.