RSpec vs Test :: Unidad en rieles

15

Nunca he estado realmente convencido de las ventajas que obtienes al cambiar a RSpec desde Test :: Unit en Ruby on Rails (a pesar de leer de vez en cuando sobre RSpec).

¿Qué tiene RSpec que la mayoría de los proyectos de Rails parecen estar usándolo?

(Algunos ejemplos de código que indican claramente las ventajas de uno sobre el otro serían muy apreciados)

Paweł Gościcki
fuente
44
Solo 1 año después y miro con disgusto Test :: Unit ... RSpec FTW!
Paweł Gościcki
Casi duplicados en StackOverflow: RSpec vs Test :: Unidad y RSpec vs. Shoulda
sondra.kinsey

Respuestas:

13

Es en gran medida una cuestión de gustos, y la mayoría de las herramientas de prueba que valen su sal son compatibles. Mi preferencia personal es RSpec sobre Test :: Unit porque a) el resultado y el diseño de las pruebas se centran en lo que se supone que debe hacer el objeto bajo prueba (en oposición a lo que es el código) yb) decir 'X debería Y' tiene más sentido para mí que 'afirmar que X predicado Y'.

Para darle un poco de contexto para los puntos anteriores, aquí hay una comparación (bastante artificial) del código de salida / fuente de dos pruebas unitarias funcionalmente equivalentes, una escrita usando RSpec y la otra usando Test :: Unit.

Código bajo prueba

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

Prueba :: Unidad

 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

Prueba :: Salida de la unidad (tan llena como podría hacerlo)

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

Salida RSpec (formateador de documentación)

Ξ 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

PD: Creo que Berin (respondedor anterior) está combinando los roles de Cucumber (que surgió del proyecto RSpec pero es independiente) y RSpec. Cucumber es una herramienta para pruebas de aceptación automatizadas en un estilo BDD, mientras que RSpec es una biblioteca de códigos para pruebas que se puede usar y se usa a nivel de unidad, integración y funcional. Por lo tanto, el uso de RSpec no excluye las pruebas unitarias, es solo que usted llama a las especificaciones de sus pruebas unitarias.

Mortaja
fuente
No esperaba sentirme triste cuando vine aquí
Roman
3

Últimamente parece que Cucumber ha estado recibiendo más apoyo en la comunidad de Rails. Aquí está el argumento en pocas palabras que escuché de una entrevista con el líder de RSpec (de un viejo Podcast de Ruby on Rails).

En la comunidad ágil (en ese momento) hubo un gran impulso para el desarrollo impulsado por pruebas con el énfasis en las pruebas primero para demostrar que tenía que cambiar algo. Había algo filosóficamente mal con eso. En esencia, las pruebas son una forma de verificar que su implementación sea correcta, entonces, ¿cómo piensa de manera diferente sobre el diseño de conducción? El líder de RSpec supuso que especifiques primero, ¿y no sería genial si la especificación también verificara los resultados de tu implementación?

El cambio assertde nombre simple a shouldayuda a enfocar la mente de la manera correcta para escribir especificaciones y pensar en el diseño. Sin embargo, eso es solo una parte de la ecuación.

Más importante aún, dado que muchos creyentes de TDD afirmaban que las pruebas documentaron el diseño, la mayoría de la documentación era deficiente en el mejor de los casos. Las pruebas son bastante opacas para los no desarrolladores que no están familiarizados con el lenguaje. Incluso entonces, el diseño no es inmediatamente evidente al leer la mayoría de las pruebas.

Como objetivo secundario, RSpec ideó una forma de generar documentación escrita a partir de las especificaciones. Es esta especificación escrita la que le da a RSpec una ventaja sobre Test :: Unit simple para impulsar el diseño de una aplicación. ¿Por qué escribir algo más de una vez cuando puede documentar y verificar la coherencia del diseño al mismo tiempo?

Entiendo que Cucumber, que tuvo el beneficio de venir más tarde y aprender lecciones de RSpec, hace un mejor trabajo de este objetivo secundario sin perder el objetivo primario (capacidad de probar la implementación a partir de la especificación). Cucumber hace esto con una API bastante inglesa como la que los no programadores pueden asimilar razonablemente. Es posible que necesiten ayuda de los programadores para completar algunas definiciones de nuevos métodos de verificación, pero está diseñado para ser extensible.

La conclusión es que RSpec / Cucumber no debería reemplazar las pruebas unitarias por completo. Es posible que sean más adecuados para documentar y verificar su diseño, pero hay varias pruebas de implementación que aún deben hacerse, particularmente con errores sutiles que se derivan de la implementación y no del diseño de la aplicación. Sin embargo, reduce la cantidad de pruebas que tiene que escribir.

Berin Loritsch
fuente