RSpec vs Test :: Unité dans les rails

15

Je n'ai jamais été vraiment convaincu des avantages que vous obtenez en passant à RSpec à partir de Test :: Unit dans Ruby on Rails (malgré la lecture de temps en temps de RSpec).

Qu'est-ce que RSpec fait que la plupart des projets Rails semblent l'utiliser?

(certains exemples de code indiquant clairement les avantages de l'un par rapport à l'autre seraient très appréciés)

Paweł Gościcki
la source
4
Seulement 1 an plus tard et je regarde avec dégoût Test :: Unit ... RSpec FTW!
Paweł Gościcki
Presque doublons sur StackOverflow: RSpec vs Test :: Unit et RSpec vs Shoulda
sondra.kinsey

Réponses:

13

C'est en grande partie une question de goût, et la plupart des outils de test valent leur soutien en sel. Ma préférence personnelle est pour RSpec plutôt que Test :: Unit car a) la sortie et la disposition des tests se concentrent sur ce que l'objet sous test est censé faire (par opposition à ce que le code est) et b) en disant 'X devrait Y' est plus logique pour moi que «d'affirmer que X prédique Y».

Pour vous donner un peu de contexte pour les points ci-dessus, voici une comparaison (assez artificielle) du code de sortie / source de deux tests unitaires fonctionnellement équivalents, l'un écrit en utilisant RSpec et l'autre en utilisant Test :: Unit.

Code sous test

class DeadError < StandardError; end

class Dog
  def bark
    raise DeadError.new "Can't bark when dead" if @dead
    "woof"
  end

  def die
    @dead = true
  end
end

Test :: Unité

 require 'test/unit'
  require 'dog'

  class DogTest < Test::Unit::TestCase
    def setup
      @dog = Dog.new
    end

    def test_barks
      assert_equal "woof", @dog.bark    
    end

    def test_doesnt_bark_when_dead
      @dog.die
      assert_raises DeadError do
        @dog.bark
      end
    end
  end

RSpec

require 'rspec'
require 'dog'

describe Dog do
  before(:all) do
    @dog = Dog.new
  end

  context "when alive" do
    it "barks" do
      @dog.bark.should == "woof"
    end
  end

  context "when dead" do
    before do
      @dog.die
    end

    it "raises an error when asked to bark" do
      lambda { @dog.bark }.should raise_error(DeadError)
    end
  end
end

Test :: Sortie unitaire (aussi complète que possible)

Ξ code/examples → ruby dog_test.rb --verbose
Loaded suite dog_test
Started
test_barks(DogTest): .
test_doesnt_bark_when_dead(DogTest): .

Finished in 0.004937 seconds.

Sortie RSpec (formateur de documentation)

Ξ code/examples → rspec -fd dog_spec.rb 

Dog
  when alive
    barks
  when dead
    raises an error when asked to bark

Finished in 0.00224 seconds
2 examples, 0 failures

2 tests, 2 assertions, 0 failures, 0 errors

PS Je pense que Berin (répondeur précédent) confond les rôles de Cucumber (qui est issu du projet RSpec mais est indépendant) et RSpec. Le concombre est un outil pour les tests d'acceptation automatisés dans un style BDD, tandis que RSpec est une bibliothèque de code pour les tests qui peut être et est utilisée aux niveaux unitaire, d'intégration et fonctionnel. Par conséquent, l'utilisation de RSpec n'empêche pas les tests unitaires - c'est simplement que vous appelez les spécifications de vos tests unitaires.

Mortaise
la source
Je ne m'attendais pas à me sentir triste quand je suis venu ici
Roman
3

Dernièrement, il semble que Cucumber ait obtenu plus de soutien dans la communauté Rails. Voici l'argument en bref que j'ai entendu d'une interview avec le plomb de RSpec (d'un vieux podcast Ruby on Rails).

Dans la communauté agile (à l'époque), il y avait une grande poussée pour le développement piloté par les tests, l'accent étant mis sur les tests d'abord pour prouver que vous deviez changer quelque chose. Il y avait quelque chose de philosophiquement incorrect avec ça. Essentiellement, les tests sont un moyen de vérifier que votre mise en œuvre est correcte, alors comment pensez-vous différemment de la conception de la conduite? Le responsable de RSpec a supposé que vous spécifiez d' abord, et ne serait-ce pas formidable si la spécification vérifiait également les résultats de votre implémentation?

Le simple changement assertde nom shouldpermet de concentrer l'esprit de la bonne manière pour rédiger des spécifications et de penser à la conception. Cependant, ce n'est qu'une partie de l'équation.

Plus important encore, étant donné que de nombreux croyants TDD affirmaient que les tests documentaient la conception, la plupart des documents étaient au mieux pauvres. Les tests sont assez opaques pour les non-développeurs peu familiers avec le langage. Même dans ce cas, la conception n'apparaît pas immédiatement à la lecture de la plupart des tests.

Donc, comme objectif secondaire, RSpec a conçu un moyen de générer une documentation écrite à partir des spécifications. C'est cette spécification écrite qui donne à RSpec un avantage sur le Test :: Unit simple pour piloter la conception d'une application. Pourquoi écrire quelque chose plus d'une fois alors que vous pouvez documenter et vérifier la cohérence de la conception en même temps?

Ma compréhension est que le concombre, qui avait l'avantage de venir plus tard et de tirer des leçons de RSpec, fait un meilleur travail de cet objectif secondaire sans perdre l'objectif principal (capacité de tester la mise en œuvre à partir des spécifications). Cucumber le fait avec une API assez anglaise que les non-programmeurs peuvent raisonnablement grogner. Ils peuvent avoir besoin de l'aide des programmeurs pour remplir certaines définitions des nouvelles méthodes de vérification, mais il est conçu pour être extensible.

L'essentiel est que RSpec / Cucumber ne devrait pas remplacer complètement les tests unitaires. Ils peuvent être mieux adaptés à la documentation et à la vérification de votre conception - mais plusieurs tests d'implémentation doivent encore être effectués, en particulier avec des bogues subtils qui découlent de l'implémentation et non de la conception de l'application. Cela réduit cependant le nombre de tests que vous devez écrire.

Berin Loritsch
la source