Dois-je toujours utiliser Debug.Assert aujourd'hui?

23

J'ai récemment rencontré du code nouvellement écrit qui était entrecoupé de beaucoup de Debug.Assert (C #).

Devrions-nous encore l'utiliser largement malgré l'utilisation du TDD, du BDD et des tests unitaires en général?

Dominik Fretz
la source
9
Je ne vois pas comment l'un exclut l'autre.
superM
2
@superM J'ai certainement vu des développeurs paresseux ajouter des tests comme des assertions avant car ils avaient écrit leur code de telle sorte qu'il était difficile de se moquer des dépendances. Inutile de dire que je ne recommanderais pas cela
jk.

Réponses:

23

Je ne vois aucune raison pour laquelle vous ne devriez pas utiliser Assert. Ce faisant, vous avez déjà reconnu le besoin de gardes, comme les conditions préalables et les invariants, et vous vous dirigez vers la conception par contrat . L'affirmation n'est qu'un moyen d'y parvenir ...

// 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);
}

Ce sont toutes des façons de réaliser la même chose: la robustesse du code. Il s'agit simplement de choisir une option, dont Assert est un choix valide.

Notez que je n'ai pas du tout mentionné de tests unitaires jusqu'à présent, car ils accomplissent quelque chose de très différent. Un test unitaire prouve formellement la robustesse du code en exerçant une garde:

[Test]
void SomeMethod_WhenGivenNull_ThrowsArgumentNullException()
{
    delegate call = () => someObject.SomeMethod(null);

    Assert.That(call).Throws<ArgumentNullException>();
}

Il s'agit d'un type d'affirmation entièrement différent ...

** Notez que dans certains frameworks, il est en fait assez difficile de tester unitaire pour un échec d'assertion, car un échec d'assertion peut faire baisser le temps d'exécution, donc l'une des autres options peut être préférée ... *

MattDavey
la source
10

Je considère les assertions et les tests unitaires comme deux outils différents dans ma boîte à outils. Certaines choses sont mieux adaptées à l'une, et certaines sont mieux adaptées à l'autre.

À titre d'exemple, ces jours-ci, j'utilise principalement des assertions pour valider les paramètres des méthodes non publiques.

vaughandroid
la source
5

Je considère Debug.Assert comme une optimisation prématurée de nos jours. Sauf si vous avez vraiment besoin des performances, la suppression de l'assertion en mode de publication peut masquer les bogues plus longtemps.

Comme MattDavey le fait remarquer , les contrats de code peuvent être supérieurs, fournissant une vérification statique au lieu d'une vérification dynamique, et s'ils ne sont pas disponibles, je préférerais Trace.Assert ou un simple ancienif(x) throw SomeException;

jk.
la source
4
Il convient de mentionner que la génération de code avec Visual Studio en mode de publication entraînera le saut de tous les appels aux méthodes de la Debugclasse ... donc la suppression d'appels à Assertsimplement pour des performances n'est pas seulement une optimisation prématurée, c'est un non-sens.
Konamiman
@Konamiman c'est le point, je veux presque toujours qu'il échoue de la même manière en mode release:. Debug.Assert ne m'est d'aucune utilité 97% du temps
jk.
Qu'est-ce que ces 3% alors, @jk? Uniquement le code hérité ou une autre instance?
DougM
@DougM performance critique code, c'est une référence à la citation de knuth. J'ajouterais également que je pense que le bogue Heartbleed démontre que ma vue est la bonne, à moins que vous n'ayez pas d'autre choix, n'élidez pas les vérifications des conditions préalables dans votre code de version
jk.