RSpec vs Test :: Unidade no Rails

15

Eu nunca estive realmente convencido das vantagens que você obtém ao migrar para o RSpec em Test :: Unit no Ruby on Rails (apesar de ler de vez em quando sobre o RSpec).

O que há no RSpec que a maioria dos projetos Rails parece estar usando?

(alguns exemplos de código que indicam claramente as vantagens de um sobre o outro seriam muito apreciados)

Paweł Gościcki
fonte
4
Apenas 1 ano depois e eu olho com desgosto para o Test :: Unit ... RSpec FTW!
Paweł Gościcki
Quase duplicatas no StackOverflow: RSpec vs Test :: Unit e RSpec vs Shoulda
sondra.kinsey

Respostas:

13

É em grande parte uma questão de gosto, e a maioria das ferramentas de teste vale o apoio de ambos. Minha preferência pessoal é por RSpec sobre Test :: Unit porque a) a saída e o layout dos testes se concentram no que o objeto em teste deve fazer (em oposição ao código) eb) dizendo 'X deve Y' faz mais sentido para mim do que "afirmar que X predica Y".

Para fornecer um contexto para os pontos acima, aqui está uma comparação (bastante artificial) do código de saída / fonte de dois testes de unidade equivalentes em termos funcionais, um escrito usando o RSpec e o outro usando Test :: Unit.

Código em teste

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

Teste :: Unidade

 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

Teste: Saída da unidade (o mais cheio possível)

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

Saída RSpec (formatador de documentação)

Ξ 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: Eu acho que Berin (respondedor anterior) está confundindo os papéis de Pepino (que surgiu do projeto RSpec, mas é independente) e RSpec. O pepino é uma ferramenta para testes de aceitação automatizados no estilo BDD, enquanto o RSpec é uma biblioteca de códigos para testes que podem ser e são usados ​​nos níveis de unidade, integração e funcionalidade. Portanto, o uso do RSpec não exclui o teste de unidade - basta chamar as especificações de teste de unidade.

Embutir
fonte
Não estava à espera de se sentir triste quando cheguei aqui
Roman
3

Ultimamente, parece que a Cucumber vem obtendo mais suporte na comunidade Rails. Aqui está o argumento resumido que ouvi de uma entrevista com o líder do RSpec (de um antigo Ruby on Rails Podcast).

Na comunidade ágil (na época), houve um grande impulso para o Desenvolvimento Orientado a Testes, com ênfase nos testes primeiro para provar que você tinha que mudar alguma coisa. Havia algo filisoficamente errado nisso. Em essência, o teste é uma maneira de verificar se sua implementação está correta. Então, como você pensa de maneira diferente sobre o design de direção? O líder do RSpec supôs que você especificasse primeiro e não seria ótimo se a especificação também verificasse os resultados da sua implementação?

A simples renomeação assertde shouldajuda a focar a mente da maneira correta de escrever especificações e pensar em design. No entanto, isso é apenas parte da equação.

Mais importante, como muitos defensores do TDD estavam reivindicando que os testes documentavam o design, a maior parte da documentação era ruim. Os testes são bastante opacos para os não desenvolvedores não familiarizados com o idioma. Mesmo assim, o design não é imediatamente aparente na leitura da maioria dos testes.

Portanto, como objetivo secundário, o RSpec criou uma maneira de gerar documentação escrita a partir das especificações. É essa especificação escrita que dá ao RSpec uma vantagem sobre o simples Test :: Unit para impulsionar o design de um aplicativo. Por que escrever algo mais de uma vez quando é possível documentar e verificar a consistência do design ao mesmo tempo?

Meu entendimento é que o Pepino, que teve o benefício de vir mais tarde e aprender lições do RSpec, realiza um trabalho melhor desse objetivo secundário sem perder o objetivo principal (capacidade de testar a implementação a partir da especificação). O Pepino faz isso com uma API do tipo inglês, que os não programadores podem razoavelmente grunhir. Eles podem precisar de ajuda dos programadores para preencher algumas definições dos novos métodos de verificação, mas foram projetados para serem extensíveis.

O ponto principal é que o RSpec / Pepino não deve substituir completamente os testes de unidade. Eles podem ser mais adequados para documentar e verificar seu design - mas existem vários testes de implementação que ainda precisam ser realizados, principalmente com erros sutis que derivam da implementação e não do design do aplicativo. No entanto, reduz o número de testes que você precisa escrever.

Berin Loritsch
fonte