RSpec vs Test :: Unit in Rails

15

Ich war noch nie wirklich von den Vorteilen überzeugt, die Sie durch den Wechsel von Test :: Unit zu RSpec in Ruby on Rails erhalten (obwohl ich von Zeit zu Zeit etwas über RSpec gelesen habe).

Was ist an RSpec, dass das meiste Rails-Projekt es zu verwenden scheint?

(Einige Codebeispiele, die die Vorteile der einen gegenüber der anderen verdeutlichen, wären sehr willkommen.)

Paweł Gościcki
quelle
4
Nur 1 Jahr später und ich schaue mit Abscheu auf Test :: Unit ... RSpec FTW!
Paweł Gościcki
Nahezu Duplikate auf StackOverflow: RSpec vs. Test :: Unit und RSpec vs. Shoulda
sondra.kinsey

Antworten:

13

Es ist größtenteils Geschmackssache, und die meisten Testwerkzeuge sind es wert, beide zu unterstützen. Ich persönlich bevorzuge RSpec gegenüber Test :: Unit, weil a) die Ausgabe und das Layout der Tests darauf abzielen, was das zu testende Objekt tun soll (im Gegensatz zum Code) und b) "X sollte Y" sagen. macht für mich mehr Sinn, als zu behaupten, dass X das Prädikat Y ist.

Um Ihnen einen gewissen Kontext für die obigen Punkte zu geben, ist hier ein (ziemlich erfundener) Vergleich des Ausgabe- / Quellcodes von zwei funktional äquivalenten Unit-Tests, von denen einer mit RSpec und der andere mit Test :: Unit geschrieben wurde.

Code im 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 :: Geräteausgabe (so voll wie ich es machen konnte)

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

RSpec-Ausgabe (Dokumentationsformatierer)

Ξ 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 Ich denke, Berin (vorheriger Responder) bringt die Rollen von Cucumber (die aus dem RSpec-Projekt hervorgegangen sind, aber unabhängig sind) und RSpec zusammen. Cucumber ist ein Tool für automatisierte Akzeptanztests im BDD-Stil, während RSpec eine Codebibliothek für Tests ist, die auf Einheiten-, Integrations- und Funktionsebene verwendet werden kann und wird. Daher schließt die Verwendung von RSpec Komponententests nicht aus - Sie nennen Ihre Komponententests nur "Spezifikationen".

Einsteckschloss
quelle
Ich hatte nicht erwartet, traurig zu sein, als ich hierher kam
Roman
3

In letzter Zeit scheint Cucumber mehr Unterstützung in der Rails-Community zu bekommen. Hier ist das kurze Argument, das ich aus einem Interview mit RSpecs Lead (aus einem alten Ruby on Rails-Podcast) gehört habe.

In der agilen Community gab es (zu der Zeit) einen großen Schub für Test Driven Development, mit dem Schwerpunkt, zuerst zu testen, um zu beweisen, dass man etwas ändern musste. Daran stimmte etwas Philisophisches nicht. Testen ist im Wesentlichen eine Möglichkeit, um zu überprüfen, ob Ihre Implementierung korrekt ist. Wie beurteilen Sie das Fahrdesign also anders? Der von Ihnen angegebene Vorsprung von RSpec wurde vermutet zuerst , und wäre es nicht großartig, wenn die Spezifikation auch die Ergebnisse Ihrer Implementierung überprüfte?

Das einfache Umbenennen assertinshould hilft dabei, den Geist auf die richtige Art und Weise zu fokussieren, um Spezifikationen zu schreiben und über Design nachzudenken. Dies ist jedoch nur ein Teil der Gleichung.

Wichtiger noch, da viele TDD-Anhänger behaupteten, dass die Tests das Design dokumentierten, war die meiste Dokumentation bestenfalls mangelhaft. Tests sind für Nicht-Entwickler, die mit der Sprache nicht vertraut sind, ziemlich undurchsichtig. Selbst dann ist das Design bei den meisten Tests nicht sofort erkennbar.

Als sekundäres Ziel entwickelte RSpec eine Möglichkeit, aus den Spezifikationen eine schriftliche Dokumentation zu erstellen. Es ist diese schriftliche Spezifikation, die RSpec einen Vorteil gegenüber der einfachen Test :: Unit verschafft, um das Design einer Anwendung voranzutreiben. Warum etwas mehrmals schreiben, wenn Sie gleichzeitig die Designkonsistenz dokumentieren und überprüfen können?

Ich verstehe, dass Gurke, die den Vorteil hatte, später zu kommen und Lehren aus RSpec zu ziehen, dieses sekundäre Ziel besser erfüllt, ohne das primäre Ziel zu verlieren (Fähigkeit, die Implementierung anhand der Spezifikation zu testen). Cucumber tut dies mit einer ziemlich englischen API, die Nicht-Programmierer vernünftigerweise verachten können. Sie benötigen möglicherweise Hilfe von Programmierern, um einige Definitionen für neue Überprüfungsmethoden auszufüllen, diese sind jedoch erweiterbar.

Fazit ist, dass RSpec / Cucumber das Testen von Einheiten nicht komplett ersetzen sollte. Sie sind möglicherweise besser geeignet, um Ihr Design zu dokumentieren und zu überprüfen. Es müssen jedoch noch einige Implementierungstests durchgeführt werden, insbesondere bei subtilen Fehlern, die von der Implementierung und nicht vom Design der Anwendung herrühren. Es reduziert jedoch die Anzahl der Tests, die Sie schreiben müssen.

Berin Loritsch
quelle