RSpec: como testar se um método foi chamado?


112

Ao escrever testes RSpec, eu me pego escrevendo uma grande quantidade de código parecido com este para garantir que um método foi chamado durante a execução de um teste (para fins de argumentação, digamos que não posso realmente interrogar o estado do objeto após a chamada porque a operação que o método executa não é fácil de ver o efeito).

describe "#foo"
  it "should call 'bar' with appropriate arguments" do
    called_bar = false
    subject.stub(:bar).with("an argument I want") { called_bar = true }
    subject.foo
    expect(called_bar).to be_true
  end
end

O que eu quero saber é: existe uma sintaxe melhor disponível do que esta? Estou perdendo alguma grandiosidade funky RSpec que reduziria o código acima a algumas linhas? should_receiveparece que deveria fazer isso, mas lendo mais parece que não é exatamente o que faz.



@Peter Alfvin O OP estava pedindo sintaxe em should_receive, então pensei que essa pergunta ajudaria.
kddeisz

Respostas:


141
it "should call 'bar' with appropriate arguments" do
  expect(subject).to receive(:bar).with("an argument I want")
  subject.foo
end

1
Desculpe, não estou entendendo como esse formato de "to .. receive (: bar)" verifica o valor de "called_bar" neste exemplo. Você pode me explicar isso?
ecoding5

2
@ ecoding5 não. Não faz e nem deve verificar called_bar. Isso foi apenas um sinalizador para garantir que o método foi chamado, mas com expect(...).to receive(...)você já está cobrindo isso. É mais claro e semântico
wacko

@wacko oooh, entendi, obrigado por esclarecer isso. Eu não percebi da primeira vez.
ecoding5


37

O abaixo deve funcionar

describe "#foo"
  it "should call 'bar' with appropriate arguments" do
     subject.stub(:bar)
     subject.foo
     expect(subject).to have_received(:bar).with("Invalid number of arguments")
  end
end

Documentação: https://github.com/rspec/rspec-mocks#expecting-arguments


Obrigado - estava recebendo "NoMethodError" has_received? - acho que isso pode ter a ver com versoins rspec. Eu encontrei outra solução que funcionou para mim (aquela marcada como correta acima)
Mikey Hogarth

@MikeyHogarth Esta resposta estava sugerindo have_received(a abordagem de "espiões" após o fato), não has_received, o que não faz parte de nenhuma versão do RSpec que eu conheço.
Peter Alfvin de

2

Para estar em total conformidade com a sintaxe RSpec ~> 3.1 e rubocop-rspeca opção padrão de regra RSpec/MessageSpies, aqui está o que você pode fazer com spy:

As expectativas da mensagem colocam a expectativa de um exemplo no início, antes de você invocar o código em teste. Muitos desenvolvedores preferem usar um padrão organizar-agir-afirmar (ou dado-quando-então) para testes de estruturação. Spies são um tipo alternativo de teste duplo que suporta esse padrão, permitindo que você espere que uma mensagem tenha sido recebida após o fato, usando have_received.

# arrange.
invitation = spy('invitation')

# act.
invitation.deliver("foo@example.com")

# assert.
expect(invitation).to have_received(:deliver).with("foo@example.com")

Se você não usar rubocop-rspec ou usando a opção não padrão. Você pode, é claro, usar o padrão RSpec 3 com o expect.

dbl = double("Some Collaborator")
expect(dbl).to receive(:foo).with("foo@example.com")
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.