O que está errado com esse teste?

#automated-test, #dev, #ruby

Os exemplos aqui estão em “plain Ruby”, mas eu tirei de um projeto Ruby on Rails.


E se eu tivesse um teste assim:

describe User do
  it "should upcase its own name" do
    user = User.new
    user.name = "alice"
    user.upcase_name!
    expect(user.name).to eq "ALICE"
  end
end

O que você acha que está errado com ele?

Mas e se eu te mostrasse isso:

describe User do
  context "when a user has a name" do
    subject { User.new }
    before { subject.name = "alice" }

    it { expect { subject.upcase_name! }.to change { subject.name }.to("ALICE") }
  end
end

Ficou melhor? Mais difícil de ler?

Comente abaixo o que você acha, eu vou adicionar apenas alguns pontos:

Sempre tenha um subject

Espera-se que todo test (i. e., it) tenha um subject. É a principal razão do teste, é o alvo do código do teste.

Sempre que procuro entender um teste eu procuro primeiro pelo subject, quem ele é, como ele é inicialmente, …

Se o seu subject não é construído pelo new/initialize crie-o usando um bloco subject {}. Será mais fácil de ler.

O subject deve ser do mesmo tipo do describe mais em cima

Se o seu describe mais externo/superior é um describe User o que você, quando lê o teste, espera que seja testado? Um usuário, certo? Não faça bagunça com isso.

Procure descrever o comportamento certo do seu código

Ok, ok, ok, não vamos falar sobre TDD vs BDD, Test::Unit vs RSpec. Continue lendo.

Este é o comportamento do seu código.

Quando eu chamo upcase_name! alguma mudança ocorre no nome do usuário

Então… escreva teste para isso. Continue lendo.

Se você tiver este código:

def name=(name)
  @name = name.upcase
end

E (não importa o motivo) também tem o upcase_name! você precisa de dois tests.

Com este código, o que re-escrevi vai falhar, por que no meu teste eu explicitamente falei que a mudança ocorre quando chamo o upcase_name!.

Com este método name= espera-se que o teste seja mais ou menos assim:

describe User do
  it "should always store name as upcase" do
    subject.name = "alice"
    expect(subject.name).to eq "ALICE"
  end
end

Bônus

Compare a saída do rspec --format documentation:

$ rspec spec/foo_spec.rb --format documentation

User
  should upcase its own name
  #upcase_name!
    should change `subject.name` to "ALICE"
  should always store name as upcase

Finished in 0.02947 seconds (files took 0.16243 seconds to load)
3 examples, 0 failures