web-dev-qa-db-fra.com

Comment déclarer une variable partagée entre des exemples dans RSpec?

Supposons que j'ai la spécification suivante:

...
describe Thing do

  it 'can read data' do
     @data = get_data_from_file  # [ '42', '36' ]
     expect(@data.count).to eq 2
  end

  it 'can process data' do
     expect(@data[0].to_i).to eq 42  # Fails because @data is nil
  end

end
...

Tout ce que je voulais, c'est avoir une variable partagée dans le décrire ou contexte donné. J'écrirais une valeur dans un exemple et la lirais dans un autre. Comment je fais ça?

36
Andrey Esperanza

Vous devez utiliser le bloc before(:each) ou before(:all):

describe Thing do
  before(:each) do
    @data = get_data_from_file  # [ '42', '36' ]
  end

  it 'can read data' do
    expect(@data.count).to eq 2
  end

  it 'can process data' do
    expect(@data[0].to_i).to eq 42
  end
end

La différence est que before(:each) sera exécutée séparément pour chaque cas et before(:all) une fois avant tous les exemples de ce describe/context. Je vous recommande de préférer before(:each) à before(:all), car chaque exemple sera isolé dans ce cas, ce qui est une bonne pratique.

Il existe de rares cas où vous souhaitez utiliser before(:all), par exemple si votre get_data_from_file A un temps d'exécution long, dans ce cas, vous pouvez, bien sûr, sacrifier l'isolement des tests au profit de la vitesse. Mais je tiens à vous informer que lorsque vous utilisez before(:all), la modification de votre variable @data Dans un test (bloc it) entraînera des conséquences inattendues pour d'autres tests dans describe/context Portée car ils la partageront.

before(:all) exemple:

describe MyClass do
  before(:all) do
    @a = []
  end

  it { @a << 1; p @a }
  it { @a << 2; p @a }
  it { @a << 3; p @a }
end

Sortira:

[1]
[1, 2]
[1, 2, 3]

[~ # ~] mis à jour [~ # ~]

Pour répondre à votre question

describe MyClass do
  before(:all) do
    @a = []
  end

  it { @a = [1]; p @a }
  it { p @a }
end

Sortira

[1]
[]

Parce que dans le premier it vous affectez localement la variable d'instance @a, donc ce n'est pas la même chose avec @a dans le bloc before(:all) et n'est pas visible pour les autres blocs it , vous pouvez le vérifier en sortant object_id s. Donc, seule la modification fera l'affaire, l'affectation entraînera la création de nouveaux objets.

Donc, si vous attribuez des variables plusieurs fois, vous devriez probablement vous retrouver avec un bloc it et plusieurs attentes. C'est acceptable, selon les meilleures pratiques.

45
Rustam A. Gasanov

C'est vraiment le but de RSpec let helper qui vous permet de le faire avec votre code:

...
describe Thing do
  let(:data) { get_data_from_file }

  it 'can read data' do
     expect(data.count).to eq 2
  end

  it 'can process data' do
     expect(data[0].to_i).to eq 42
  end

end
...
11
Anthony

Je viens de rencontrer ce même problème. Comment j'ai résolu le problème en utilisant factory_girl gem.

Voici les bases:

créer une usine (voici un extrait de code:

require 'factory_girl'
require 'faker' # you can use faker, if you want to use the factory to generate fake data

FactoryGirl.define do
  factory :generate_data, class: MyModule::MyClass do
    key 'value'
  end
end

Maintenant, après avoir fait l'usine, vous devez créer un modèle qui ressemble à ceci:

Module MyModule
  class MyClass
    attr_accessor :key

    #you can also place methods here to call from your spec test, if you wish
    # def self.test
        #some test
    # end
  end
end

Maintenant, pour revenir à votre exemple, vous pouvez faire quelque chose comme ceci:

describe Thing do
  before(:all) do
  @data = FactoryGirl.build(:generate_data)
  end

  it 'can read data' do
     @data.key = get_data_from_file  # [ '42', '36' ]
     expect(@data.key.count).to eq 2
  end

  it 'can process data' do
     expect(@data.key[0].to_i).to eq 42  # @data will not be nil. at this point. whatever @data.key is equal to last which was set in your previous context will be what data.key is here
  end

end

Quoi qu'il en soit, bonne chance, dites-nous si vous avez une autre solution!

0
adbarads