Pergunta

class A
  def initialize
    @x = do_something
  end

  def do_something
    42
  end
end

Como posso stub do_something em rspec, antes da implementação original é chamado (atribuindo, assim, 42 a @x)? E sem alterar a aplicação, é claro.

Foi útil?

Solução

Aqui está a cometer o que adiciona o recurso para rspec - Este foi em 25 de maio de 2008. Com isso, você pode fazer

A.any_instance.stub(do_something: 23)

No entanto, a versão mais recente jóia de rspec (1.1.11, outubro de 2008) não tem este patch nele.

Este bilhete estados que puxou-o para fora por motivos de manutenção, e uma solução alternativa ainda não foi fornecido.

Não parece que você pode fazê-lo neste momento. Você vai ter que cortar a classe manualmente usando alias_method ou algo assim.

Outras dicas

Eu encontrei esta solução no http://pivotallabs.com/introducing-rr/

new_method = A.method(:new)

A.stub!(:new).and_return do |*args|
  a = new_method.call(*args)
  a.should_receive(:do_something).and_return(23)
  a
end

Eu não sei como fazer isso no quadro de simulação de spec, mas você pode facilmente trocá-lo por mocha para fazer o seguinte:

# should probably be in spec/spec_helper.rb
Spec::Runner.configure do |config|
  config.mock_with :mocha
end

describe A, " when initialized" do
  it "should set x to 42" do
    A.new.x.should == 42
  end
end

describe A, " when do_something is mocked" do
  it "should set x to 23" do
    A.any_instance.expects(:do_something).returns(23)
    A.new.x.should == 23
  end
end

ou com RR :

stub.any_instance_of(A).do_something { 23 }

Na versão mais recente do RSpec a partir de hoje - 3.5 você pode:

allow_any_instance_of(Widget).to receive(:name).and_return("Wibble")

Eu gosto de resposta Denis Barushev. E eu gostaria de sugerir apenas uma mudança cosmética que torna variável new_method desnecessário. Rspec faz munge em métodos stubbed, para que eles possam ser acessados ??com proxied_by_rspec__ prefixo:


A.stub!(:new).and_return do |*args|
  a = A.proxied_by_rspec__new(*args)
  a.should_receive(:do_something).and_return(23)
  a
end

Em RSpec 2.6 ou posterior você pode usar

A.any_instance.stub(do_something: 23)

Veja os docs para mais detalhes. (Graças a rogerdpack por apontar que isso agora é possível - eu pensei que merecia uma resposta do seu próprio)

Para stub um método de instância, você pode fazer algo como isto:

before :each do
  @my_stub = stub("A")
  @my_stub.should_receive(:do_something).with(no_args()).and_return(42)
  @my_stub.should_receive(:do_something_else).with(any_args()).and_return(true)
  A.stub(:new).and_return(my_stub)
end

Mas, como pschneider apontou, basta retornar 42 na nova com: A.stub(:new).and_return(42) ou algo nesse sentido.

Aqui está uma idéia que pode não ser muito elegante, mas é basicamente a certeza de trabalho:

Criar uma pequena classe que herda a classe que você deseja testar, substituir o método e chamada initialize super depois ter criado os canhotos na inicialização, assim:

it "should call during_init in initialize" do
  class TestClass < TheClassToTest
    def initialize
      should_receive(:during_init)
      super
    end
  end
  TestClass.new
end

E lá vai você! Eu apenas usei isso com sucesso em um dos meus testes.

O rspec_candy gem vem com um método auxiliar stub_any_instance que funciona em ambos RSpec 1 e RSpec 2.

Na minha versão do rspec (1.2.2) eu posso fazer isso:

A.should_receive(:new).and_return(42)

Eu sei que é provavelmente tarde demais para responder ao autor, mas eu respondê-la de qualquer maneira para referência futura, como eu vim aqui com a mesma pergunta, mas figura para fora ele estava trabalhando na versão mais recente rspec.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top