Forum: Italian Ruby user group Rspec, scope di un metodo before

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
3ca4ad042effe02400fde5524f25edc1?d=identicon&s=25 Iwan B. (1w4n)
on 2015-07-24 10:50
Prima l'esempio dummy:

class Product < ActiveRecord::Base
  validates :code, uniqueness: true

  # ...

  def clone
    Product.create(code: "New #{code}", description: description)
  end
end


describe Product, type: :model do
  it "is valid" do
    expect(build(:product)).to be_valid
  end

  describe "cloned object" do
    before :context do
      @pr = create(:product)
      @cl = @pr.clone
    end

    it "has different code" do
      expect(@cl.code).not_to eq(@pr.code)
    end

    it "has same description" do
      expect(@cl.description).to eq(@pr.description)
    end

    it ...

  end

end


La descrizione del mio problema:

Vorrei testare il corretto comportamento del metodo 'clone' di Product
verificando che la copia abbia tutti gli attributi uguali (tranne
l'attributo code).
Per fare ciò ho inserito un blocco 'before :context' che mi crea
l'originale e il suo clone e poi vado a testare ogni attributo.
Inserisco il tutto in un blocco 'describe' (o 'context') con la
convinzione che il before venga eseguito solo per gli esempi all'interno
di esso.
E invece no: il blocco 'before :context' viene eseguito anche fuori dal
blocco, nell'esempio mostrato viene eseguito anche prima dell'esempio
'is valid', e la validazione non passa in quanto il build prepara un
record con un code già esistente.

Infine le domande:

- è possibile separare il metodo 'before' per applicarlo solo ad un
sottoinsieme di esempi?
- quale è la best practice in una situazione del genere?


Grazie mille per tutti i contributi e le risposte.

Ciao

i.
32d80da41830a6e6c1bb3eb977537e3e?d=identicon&s=25 Alessandro R. (alessandro_r)
on 2015-07-27 16:18
(Received via mailing list)
usa before(:each) do

Alessandro Rodi
D538ad2e054ac7dbf934fa47386d7286?d=identicon&s=25 Nicolò Gnudi (nickgnd)
on 2015-07-28 23:59
Ciao Iwan,
ho provato a replicare il tuo esempio in maniera simile e nel mio caso
il blocco "before(:context)" viene eseguito solo una volta: prima dei
due blocchi "it" come da manuale.
Ti riporto qui sotto il codice (classe+spec), puoi benissimo copiarlo e
incollarlo in un file.rb per testarlo a tua volta.
(per praticità ho sostituito la validazione dell'unicità del record con
la validazione della presenza).


# ---- product_spec.rb
require "rspec/expectations"
require "active_model"

class Product
  include ActiveModel::Validations

  attr_accessor :code, :description
  validates :code, :description, presence: true

  def initialize params = {}
    params.each { |key, value| send "#{key}=", value }
  end

  def clone
    product = Product.new code: "New #{self.code}", description:
self.description
  end
end

# SPEC
RSpec.describe Product do

  it "is valid" do
    expect(Product.new code: "1234", description: "description").to
be_valid
  end

  it "isn't valid without code" do
    expect(Product.new code: nil, description: "description").to
be_valid
  end

  describe "cloned object" do
    before(:context) do
      puts "before context -> creo product e lo clono"
      @pr = Product.new code: "1234", description: "description"
      @cl = @pr.clone
    end

    it "has different code" do
      expect(@cl.code).not_to eq(@pr.code)
    end

    it "has same description" do
      expect(@cl.description).to eq(@pr.description)
    end
  end

end

# ----------------------------

se lancio il test da terminale l'output è il seguente:

Nico$ rspec test2.rb --format documentation

Product
  is valid
  isn't valid without code
  cloned object
before context -> creo product e lo clono
    has different code
    has same description

Finished in 0.20649 seconds (files took 0.45466 seconds to load)
4 examples, 0 failures


Come vedi il "before" block viene chiamato una volta sola all'interno
della describe "cloned object" e prima dei 2 blocchi "it" al suo
interno.

Personalmente preferisco evitare l'uso di variabili di istanza se non è
strettamente necessario e uso let al suo posto.
Dai un occhio qui
http://betterspecs.org/
http://stackoverflow.com/questions/14116613/when-i...


Ciao :)

Nicolò
This topic is locked and can not be replied to.