Czy nadal powinienem używać Debug.Assert?

23

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?

Dominik Fretz
źródło
9
Nie widzę, jak jedno wyklucza drugie.
superM
2
@ superM Zdecydowanie widziałem, jak leniwi programiści dodają wcześniej testy, jak napisali swój kod, tak że trudno było wyśmiewać zależności. nie trzeba dodawać, że nie poleciłbym tego
jk.

Odpowiedzi:

23

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 ... *

MattDavey
źródło
10

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.

Vaughandroid
źródło
5

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;

jk.
źródło
4
Warto wspomnieć, że generowanie kodu za pomocą Visual Studio w trybie wydania spowoduje, że wszystkie wywołania metod tej Debugklasy zostaną pominięte podczas kompilacji ... więc tłumienie wywołań w celu zwiększenia Assertwydajności nie jest tylko przedwczesną optymalizacją, to zwykły nonsens.
Konamiman
@Konamiman o to chodzi, prawie zawsze chcę, aby zawiódł w ten sam sposób w trybie wydania:. Debug.Assert jest dla mnie bezużyteczny w 97% przypadków
jk.
Co to jest 3%, @jk? Tylko starszy kod, czy jakaś inna instancja?
DougM
@Kod krytyczny dla wydajności @DougM, jest odniesieniem do cytatu knuth. Dodam również, że myślę, że błąd serca pokazuje, że mój pogląd jest prawidłowy, chyba że nie masz innego wyboru, nie poddawaj się testom warunków wstępnych w swoim kodzie wydania
jk.