web-dev-qa-db-fra.com

Passage de paramètres à un exemple partagé rspec

J'ai un processus qui renvoie un ensemble de résultats que je veux tester pour la validité à l'aide de rspec. Le processus renverra des résultats différents en fonction des paramètres, mais il existe de nombreux exemples communs à tous. J'aimerais donc créer un ensemble d'exemples communs que je peux utiliser pour tous.

Je sais que la pratique préférée consiste à utiliser la let pour construire le résultat. Le problème est que chaque processus prend une minute ou deux pour générer un résultat et j'ai probablement 30 exemples. Avec toutes les permutations basées sur des paramètres différents, je lance environ 500 exemples. Si je devais reconstruire le résultat pour chaque exemple, le test aurait lieu plus d'une journée.

Donc, au lieu de cela, je construis un résultat dans un bloc before (: all) et l'assigne à un attribut du type suivant:

RSpec.describe 'Test Description' do
  attr_reader :result

  before(:all)
    @result = build_result({some_parameters})
  end

  context 'Some context' do
    it 'Looks lik a result' do 
      expect(result.something).to ...
    end

    it 'Feels lik a result' do 
      expect(result.something).to ...
    end
  end
end

Peut-être y a-t-il un meilleur moyen que d'utiliser un attribut. Je veux faire quelque chose comme ça:

RSpec.describe 'Test Description' do
  attr_reader :result

  before(:all)
    @result = build_result({some_parameters})
  end

  context 'Some context' do
    it_behaves_like "A result" result
  end
end

L'utilisation d'un attribut dans ce contexte échoue. Y a-t-il une manière différente de faire ceci?

12
Nth boss

Vous pouvez regrouper toutes vos assertions sur le résultat dans un seul exemple. De cette façon, la let n'est évaluée qu'une fois.

RSpec.describe 'Test Description' do
  context 'for params x and y' do
    let(:expected_x) { 'x' }
    let(:expected_y) { 'y' }

    subject { build_result({x: 'x', y: 'y'}) }

    specify :aggregate_failures do
      expect(subject.x).to eq(expected_x)
      expect(subject.y).to eq(expected_y)
    end
  end
end

Cela va à l’encontre de la ligne directrice «un test, une affirmation», mais si l’opération est très coûteuse, je pense que c’est une approche raisonnable. Avec :aggregate_failures vous obtiendrez des échecs distincts pour chaque assertion, vous ne manquerez donc pas de cela.

1
Laura Paakkinen

Vous pouvez passer des arguments à des exemples partagés comme ceci:

shared_examples_for "A result" do |argument|
 # some tests with argument
end

Et passez ensuite my_argument comme ceci:

it_behaves_like "A result", my_argument
46
Ryan Hertz

vous pouvez utiliser let.

let(:result)     { build_result({some_parameters}) }

Cela crée une variable d'instance que vous pourrez utiliser dans votre test ultérieurement.

Accorder à la documentation sur let

Lorsque vous devez affecter une variable au lieu d'utiliser un bloc avant pour Créer une variable d'instance, utilisez let. Utiliser laisser la variable lazy Ne se charge que lorsqu’elle est utilisée pour la première fois dans le test et restera mis en cache Jusqu’à la fin de ce test spécifique.

MAUVAIS

describe '#type_id' do
  before { @resource = FactoryGirl.create :device }
  before { @type     = Type.find @resource.type_id }

  it 'sets the type_id field' do
    expect(@resource.type_id).to equal(@type.id)
  end
end

BIEN

describe '#type_id' do
  let(:resource) { FactoryGirl.create :device }
  let(:type)     { Type.find resource.type_id }

  it 'sets the type_id field' do
    expect(resource.type_id).to equal(type.id)
  end
end
0
davidhu2000