Ich habe eine Modellfamilie mit einer Methode, location
die die location
Ausgaben anderer Objekte, Mitglieder, zusammenführt. (Mitglieder sind mit Familien verbunden, aber das ist hier nicht wichtig.)
Zum Beispiel gegeben
- member_1 hat
location
== 'San Diego (Reisen, Rückkehr am 15. Mai)' - member_2 hat
location
== 'San Diego'
Family.location gibt möglicherweise 'San Diego (Mitglied_1 reist, kehrt am 15. Mai zurück)' zurück. Die Einzelheiten sind unwichtig.
Um das Testen von Family.location zu vereinfachen, möchte ich Member.location stubben. Ich brauche es jedoch, um zwei verschiedene (angegebene) Werte wie im obigen Beispiel zurückzugeben. Im Idealfall würden diese auf einem Attribut von basieren member
, aber die einfache Rückgabe verschiedener Werte in einer Sequenz wäre in Ordnung. Gibt es eine Möglichkeit, dies in RSpec zu tun?
Es ist möglich, die Member.location-Methode in jedem Testbeispiel zu überschreiben, z
it "when residence is the same" do
class Member
def location
return {:residence=>'Home', :work=>'his_work'} if self.male?
return {:residence=>'Home', :work=>'her_work'}
end
end
@family.location[:residence].should == 'Home'
end
aber ich bezweifle, dass dies eine gute Praxis ist. Wenn RSpec eine Reihe von Beispielen ausführt, wird in keinem Fall die ursprüngliche Klasse wiederhergestellt, sodass diese Art der Überschreibung nachfolgende Beispiele "vergiftet".
Gibt es also eine Möglichkeit, dass eine Stubbed-Methode bei jedem Aufruf unterschiedliche, angegebene Werte zurückgibt?
quelle
my_big_array
, die Sie tun könntenallow(@family).to receive(:location).and_return(*my_big_array)
. Hoffe das hilft.RSpec 3-Syntax:
allow(@family).to receive(:location).and_return("abcdefg", "bcdefgh")
quelle
Die akzeptierte Lösung sollte nur verwendet werden, wenn Sie eine bestimmte Anzahl von Anrufen haben und eine bestimmte Datenfolge benötigen. Aber was ist, wenn Sie nicht wissen, wie viele Anrufe getätigt werden, oder sich nicht um die Reihenfolge der Daten kümmern, nur dass es jedes Mal etwas anderes ist? Wie OP sagte:
Das Problem dabei
and_return
ist, dass der Rückgabewert gespeichert wird. Das heißt, selbst wenn Sie etwas Dynamisches zurückgeben, erhalten Sie immer das Gleiche.Z.B
allow(mock).to receive(:method).and_return(SecureRandom.hex) mock.method # => 7c01419e102238c6c1bd6cc5a1e25e1b mock.method # => 7c01419e102238c6c1bd6cc5a1e25e1b
Ein praktisches Beispiel wäre die Verwendung von Fabriken und das Erhalten derselben IDs:
allow(Person).to receive(:create).and_return(build_stubbed(:person)) Person.create # => Person(id: 1) Person.create # => Person(id: 1)
In diesen Fällen können Sie den Methodenkörper stubben, damit der Code jedes Mal ausgeführt wird:
allow(Member).to receive(:location) do { residence: Faker::Address.city } end Member.location # => { residence: 'New York' } Member.location # => { residence: 'Budapest' }
Beachten Sie, dass Sie
self
in diesem Kontext keinen Zugriff auf das Member-Objekt über haben, sondern Variablen aus dem Testkontext verwenden können.Z.B
member = build(:member) allow(member).to receive(:location) do { residence: Faker::Address.city, work: member.male? 'his_work' : 'her_work' } end
quelle
Wenn Sie aus irgendeinem Grund die alte Syntax verwenden möchten, können Sie dennoch:
@family.stub(:location).and_return('foo', 'bar')
quelle
Ich habe die Lösungsübersicht hier oben ausprobiert, aber sie funktioniert bei mir nicht. Ich habe das Problem durch Stubbing mit einer Ersatzimplementierung gelöst.
Etwas wie:
@family.stub(:location) { rand.to_s }
quelle