Pergunta

Sinto muito, mas isso está começando a sentir como me chutando na cabeça. Estou completamente perplexo com RSpec. Tem vídeos assistidos após vídeo, tutorial de leitura depois de tutorial, e ainda estou apenas preso em um quadrado.

=== aqui é o que eu estou trabalhando com

http://github.com/fudgestudios/bort/tree/master

=== erros

F

1)
NoMethodError in 'bidding on an item should work'
You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.new_record?
spec/controllers/auction_controller_spec.rb:16:
spec/controllers/auction_controller_spec.rb:6:

Finished in 0.067139 seconds

1 example, 1 failure

=== aqui é a minha ação do controlador

  def bid

      @bid = Bid.new(params[:bid])
      @bid.save

  end

=== aqui é o meu teste

require File.dirname(__FILE__) + '/../spec_helper'
include ApplicationHelper
include UsersHelper
include AuthenticatedTestHelper

describe "bidding on an item" do
  controller_name :items

    before(:each) do
      @user = mock_user
      stub!(:current_user).and_return(@user)
    end

  it "should work" do
    post 'bid', :bid => { :auction_id => 1, :user_id => @user.id, :point => 1 }
    assigns[:bid].should be_new_record
  end

end

=== spec_helper

http://github.com/fudgestudios/ bort / árvore / master / spec / spec_helper.rb

É muito desanimador para acordar para o trabalho em 3:00 e conseguir nada para o dia. Por favor, entenda.

Foi útil?

Solução

Você tem um par de coisas para trás antes (: cada). Vendo como o exemplo está especificando que o cargo deve aumentar a contagem por 1, você está lidando com registros reais e não há nenhuma razão para arrancar alguma coisa. Além disso, neste momento, uma vez que existe apenas um exemplo, não há nenhuma razão para ter um bloco antes. Eu faria isso desta maneira:

describe ItemsController, "bidding on an item" do
  fixtures :users

  it "should create a new Bid" do
    login_as :quentin
    lambda do
      post 'bid', :bid => { :auction_id => 1, :user_id => @user.id, :point => 1 }
    end.should change(Bid, :count).by(1)
  end

end

Uma coisa que eu recomendo é a criação destas coisas muito granular por enquanto até que você compreendê-los melhor. Iniciar com a expectativa (pós deve mudar contagem bid), executar a especificação e deixe o guia mensagem de falha que você adicione qualquer outra coisa que você precisa na especificação ou no código.

Outras dicas

Jesse,

Ele ainda vai passar se você comentar as 2 duas linhas de antes (: cada)., Que estão tendo nenhum impacto sobre o "deve criar um novo lance" exemplo

A palavra-chave lambda cria um bloco arbitrário de código que não é executado quando você defini-lo, mas na verdade é um objeto que você pode atribuir a uma variável e executar depois:

the_post = lambda do
  post 'bid', :bid => { :auction_id => 1, :user_id => @user.id, :point => 1 }
end

Neste ponto que o código não é executado, mas podemos nos referir a ele com o 'the_post' variável. Agora nós podemos enviá-lo 'deveria', seguido de 'Alterar ...', assim:

the_post.should change(Bid, :count).by(1)

Quando esta linha é executada, algumas coisas acontecem. O material para a direita do 'deve' é avaliado primeiro, inicializar um objeto de correspondência rspec com algumas instruções. Essa correspondência é o argumento de 'deveria' - o equivalente a isso:

matcher = change(Bid, :count).by(1)
the_post.should(matcher)

O método 'deve' é chamado em the_post, que é o bloco de código (que ainda não foi executada). Sob o capô, o método 'deve' passa self (the_post) para a correspondência, assim que a correspondência agora tem tudo que precisa para avaliar o exemplo.

A correspondência chama Bid.count e registros o valor. Em seguida, ele executa o bloco (the_post), e em seguida, chama Bid.count uma segunda vez e compara com o valor que anotou anteriormente. Neste caso, uma vez que estamos procurando Bid.count à mudança por 1 (positivo está implícito aqui - aumento de 1), se é isso que acontece as estadias matcher silenciosa e o exemplo passa

.

Se os valores são os mesmos, ou diferem por algum valor diferente de 1, o exemplo falhará. Você pode ver que o trabalho se você mudar a expectativa de por (2) em vez de (1).

HTH, David

EDIT: você não deve esperar Bid.count de incremento ao usar um objeto fictício. Mantra eu esqueci: cafeína antes do código

.

Apenas comentar as linhas, por agora, de modo que o original ainda está lá.

require File.dirname(__FILE__) + '/../spec_helper'
include ApplicationHelper
include UsersHelper
include AuthenticatedTestHelper

describe "POST to bid_controller" do
  controller_name :items

  before(:each) do
        #@bid = mock_model(Bid)           # create a new mock model so we can verify the appropriate things
        #Bid.stub!(:new).and_return(@bid) # stub the new class method on Bid to return our mock rather than a new ActiveRecord object.
                                         # this separates our controller spec entirely from the database.
  end

  it "should create a new Bid" do
    lambda do
        post 'bid', :bid => { :auction_id => 1, :user_id => @user.id, :point => 1 }
    end.should change(Bid, :count).by(1)
  end

    # ... more specs
end

Tente escrever como especificações pequenas quanto possível, escrever seus setences de tal forma a torná-lo óbvio que você deve verificar em que spec. Por exemplo, como eu mudei o seu a partir it "should work" para it "should create a new Bid". Se há mais do que o controlador, escrever uma nova especificação para cada pequeno pedaço de funcionalidade.

Se você acabar precisando de usuários simulados, existem alguns ajudantes para restful_authentication que tornam mais fácil. Primeiro crie um dispositivo elétrico do usuário em RAILS_ROOT/spec/fixtures/users.yml, como este:

quentin:
  login: quentin
  email: quentin@example.com
  salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd
  crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
  created_at: <%= 5.days.ago.to_s :db %>
  activation_code: 8f24789ae988411ccf33ab0c30fe9106fab32e9b 
  activated_at: <%= 5.days.ago.to_s :db %> 
  name: "Quentin"

Então, em sua especificação você vai ser capaz de escrever o seguinte e ter o seu método current_user e todas as outras partes do restul_authentication se comportam como você esperaria que em tempo de execução.

login_as :quentin
# .... the rest of your spec

Como um exemplo de mais algumas especificações que eu poderia acrescentar como mais um par de exemplos:

def do_post
    # extracting the method under test, so I don't repeat myself
    post 'bid', :bid => { :auction_id => 1, :user_id => @user.id, :point => 1 }
end

it "should create a new Bid" do
    lambda do
    do_post
    end.should change(Bid, :count).by(1)
end

it "should assign the Bid to the proper auction" do
    @bid.should_receive(:auction_id=).with(1) # test this, I believe doing  Bid.new(params[:bid]) sets the id directly not sets the model
    do_post
end

it "should assign the Bid the proper points" do
    @bid.should_receive(:point=).with(1)
    do_post
end

Enquanto eu não entendo muito bem o que está acontecendo. (Com tocos e lambda) ....

para

def bid
  @bid = Bid.new params[:bid]
  @bid.save
end

A seguir passa !!

require File.dirname(__FILE__) + '/../spec_helper'
include ApplicationHelper
include UsersHelper
include AuthenticatedTestHelper

describe "bidding on an item" do
  controller_name :items
  fixtures :users

  before(:each) do
    @user = login_as :quentin
    @bid = mock_model(Bid)           # create a new mock model so we can verify the appropriate things
    @bid.stub!(:new).and_return(@bid) # stub the new class method on Bid to return our mock rather than a new ActiveRecord object.
    #Bid.stub!(:save).and_return(true)# this separates our controller spec entirely from the database.
  end

  it "should create a new Bid" do
    lambda do
      post 'bid', :bid => { :auction_id => 1, :user_id => @user.id, :point => 1 }
    end.should change(Bid, :count).by(1)
  end

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