web-dev-qa-db-fra.com

Rspec: attendre vs attendre avec un bloc - quelle est la différence?

Je viens d'apprendre la syntaxe rspec et j'ai remarqué que ce code fonctionne:

  context "given a bad list of players" do
    let(:bad_players) { {} }

    it "fails to create given a bad player list" do
       expect{ Team.new("Random", bad_players) }.to raise_error
     end 
  end

Mais ce code ne:

  context "given a bad list of players" do
    let(:bad_players) { {} }

    it "fails to create given a bad player list" do
       expect( Team.new("Random", bad_players) ).to raise_error
     end 
  end

Cela me donne cette erreur:

Team given a bad list of players fails to create given a bad player list
     Failure/Error: expect( Team.new("Random", bad_players) ).to raise_error
     Exception:
       Exception
     # ./lib/team.rb:6:in `initialize'
     # ./spec/team_spec.rb:23:in `new'
     # ./spec/team_spec.rb:23:in `block (3 levels) in <top (required)>'

Ma question est:

  1. Pourquoi cela arrive-t-il?
  2. Quelle est la différence entre l'ancien et le dernier exemple exactement en rubis?

Je cherche aussi règles sur quand utiliser l'un sur l'autre

Un autre exemple des mêmes résultats mais inversés, où ce code fonctionne:

  it "has a list of players" do
    expect(Team.new("Random").players).to be_kind_of Array
  end 

Mais ce code échoue

  it "has a list of players" do
    expect{ Team.new("Random").players }.to be_kind_of Array
  end

L'erreur que j'obtiens dans ce cas est:

Failure/Error: expect{ Team.new("Random").players }.to be_kind_of Array
       expected #<Proc:0x007fbbbab29580@/Users/amiterandole/Documents/current/Ruby_sandbox/tdd-Ruby/spec/team_spec.rb:9> to be a kind of Array
     # ./spec/team_spec.rb:9:in `block (2 levels) in <top (required)>'

La classe que je teste ressemble à ceci:

class Team
  attr_reader :name, :players

  def initialize(name, players = [])
    raise Exception unless players.is_a? Array

    @name = name
    @players = players
  end
end
32
Amit Erandole

Comme cela a été mentionné:

expect(4).to eq(4)

Cela teste spécifiquement la valeur que vous avez envoyée en tant que paramètre à la méthode. Lorsque vous essayez de tester les erreurs déclenchées lorsque vous faites la même chose:

expect(raise "fail!").to raise_error

Votre argument est évalué immédiatement et cette exception sera levée et votre test explosera juste là.

Cependant, lorsque vous utilisez un bloc (et c'est Ruby de base), le contenu du bloc n'est pas exécuté immédiatement - son exécution est déterminée par la méthode que vous appelez (dans ce cas, la méthode expect gère quand pour exécuter votre bloc):

expect{raise "fail!"}.to raise_error

Nous pouvons regarder un exemple de méthode qui pourrait gérer ce comportement:

def expect(val=nil)
  if block_given?
    begin
      yield
    rescue
      puts "Your block raised an error!"
    end
  else
    puts "The value under test is #{val}"
  end
end

Vous pouvez voir ici que c'est la méthode expect qui sauve manuellement votre erreur afin qu'elle puisse tester si des erreurs sont déclenchées, etc. yield est le moyen d'une méthode Ruby l'exécution du bloc transmis à la méthode.

50
nzifnab

Dans le premier cas, lorsque vous passez un bloc à expect, l'exécution du bloc ne se produit pas avant qu'il ne soit temps d'évaluer le résultat, auquel cas le code RSpec peut détecter toute erreur déclenchée et vérifier contre toute attente.

Dans le second cas, l'erreur est générée lorsque l'argument de expect est évalué, de sorte que le code expect n'a aucune chance de s'impliquer.

En ce qui concerne les règles, vous passez un bloc ou un Proc si vous essayez de tester comportement (par exemple, augmenter les erreurs, changer une valeur). Sinon, vous passez un argument "conventionnel", auquel cas la valeur de cet argument est ce qui est testé.

10
Peter Alfvin