web-dev-qa-db-fra.com

Est-il idiomatique Ruby pour ajouter une méthode assert () à la classe Kernel de Ruby?

J'étends ma compréhension Ruby en codant un équivalent de xUnit de Kent Beck dans Ruby. Python (dans lequel Kent écrit) a une méthode assert () dans le langage qui est largement utilisé. Ruby ne le fait pas. Je pense qu'il devrait être facile d'ajouter ceci mais est-ce que le noyau est le bon endroit pour le mettre?

BTW, Je connais l'existence des différents frameworks Unit dans Ruby - c'est un exercice pour apprendre les idiomes Ruby, plutôt que de "faire quelque chose").

72
Andrew Harmel-Law

Non, ce n'est pas une meilleure pratique. La meilleure analogie pour affirmer () dans Ruby soulève simplement

 raise "This is wrong" unless expr

et vous pouvez implémenter vos propres exceptions si vous souhaitez prévoir une gestion des exceptions plus spécifique

95
Julik

Je pense qu'il est tout à fait valable d'utiliser des assertions dans Ruby. Mais vous mentionnez deux choses différentes:

  • les frameworks xUnit utilisent des méthodes assert pour vérifier les attentes de vos tests. Ils sont destinés à être utilisés dans votre code de test, pas dans votre code d'application.
  • Certains langages comme C, Java ou Python, incluent une construction assert destinée à être utilisée dans le code de vos programmes, pour vérifier les hypothèses que vous faites sur leur intégrité. Ces vérifications sont construit à l'intérieur du code lui-même. Ce ne sont pas des utilitaires de test, mais des utilitaires de développement.

J'ai récemment écrit solid_assert: un peu Ruby bibliothèque implémentant un Ruby utilitaire d'assertion et aussi n post dans mon blog) expliquant sa motivation .. Il vous permet d'écrire des expressions sous la forme:

assert some_string != "some value"
assert clients.empty?, "Isn't the clients list empty?"

invariant "Lists with different sizes?" do
    one_variable = calculate_some_value
    other_variable = calculate_some_other_value
    one_variable > other_variable
end    

Et ils peuvent être désactivés pour que assert et invariant soient évalués comme des instructions vides. Cela vous permet d'éviter tout problème de performances en production. Mais notez que The Pragmatic Programmers déconseille de les désactiver. Vous ne devez les désactiver que s'ils affectent réellement les performances.

En ce qui concerne la réponse disant que la méthode idiomatique Ruby utilise une instruction normale raise, je pense qu'elle manque d'expressivité. L'une des règles d'or de la programmation assertive n'utilise pas les assertions pour la gestion normale des exceptions. Ce sont deux choses complètement différentes. Si vous utilisez la même syntaxe pour les deux, je pense que votre code sera plus obscur. Et bien sûr, vous perdez la capacité de les désactiver.

Vous pouvez être convaincu que l'utilisation d'assertions est une bonne chose car deux livres classiques à lire absolument comme The Pragmatic Programmer From Journeyman to Master and Code Complete dediez-leur des sections entières et recommandez leur utilisation. Il y a aussi un article de Nice intitulé Programmation avec assertions qui illustre très bien ce qu'est la programmation assertive et quand l'utiliser (elle est basée sur Java, mais les concepts s'appliquent à n'importe quel langage).

28
jmanrubia

Quelle est votre raison pour ajouter la méthode assert au module Kernel? Pourquoi ne pas simplement utiliser un autre module appelé Assertions ou quelque chose?

Comme ça:

module Assertions
  def assert(param)
    # do something with param
  end

  # define more assertions here
end

Si vous avez vraiment besoin que vos assertions soient disponibles partout faites quelque chose comme ceci:

class Object
  include Assertions
end

Avertissement: je n'ai pas testé le code mais en principe je le ferais comme ça.

14
Christoph Schiessl

Ce n'est pas spécialement idiomatique, mais je pense que c'est une bonne idée. Surtout si c'est fait comme ça:

def assert(msg=nil)
    if DEBUG
        raise msg || "Assertion failed!" unless yield
    end
end

De cette façon, il n'y a aucun impact si vous décidez de ne pas fonctionner avec DEBUG (ou un autre commutateur pratique, j'ai utilisé Kernel.do_assert dans le passé).

6
regularfry

Je crois comprendre que vous écrivez votre propre suite de tests afin de vous familiariser avec Ruby. Ainsi, alors que Test :: Unit peut être utile comme guide, ce n'est probablement pas ce que vous recherchez (car il a déjà fait le travail).

Cela dit, l'assertion de python est (pour moi, au moins), plus analogue à C assert (3) . Il n'est pas spécialement conçu pour les tests unitaires, mais plutôt pour détecter les cas où "cela ne devrait jamais arriver".

La façon dont les tests unitaires intégrés de Ruby ont tendance à considérer le problème est que chaque classe de cas de test est une sous-classe de TestCase , et qui comprend une instruction "assert" qui vérifie la validité de ce qui était transmis à celui-ci et l'enregistre pour rapport.

4
Atiaxi