2016-07-23 34 views
1

Ich spiele mit der Mailgun API, alle Funktionalitäten scheinen jetzt zu funktionieren und ich möchte sie mit rspec mocks testen.ruby ​​rspec mocks Test Funktion einen Hash erhalten

Ich habe einige JSON-Fixtures unter dem Ordner rspec/fixtures erstellt, jeder hat einen json, der das erwartete Ergebnis darstellt, wenn ich eine bestimmte Funktion aufruft. Ich habe auch einen kleinen Helfer:

module TestHelpers 
    def self.get_json(filename:) 
    JSON.parse File.read(filename) 
    end 
end 

Was ich testen möchten, ist diese Funktion:

def self.get_messages_for(email:) 
    sent_emails = [] 
    delivered_events = get_events_for(email: email) 

    # :Accept => "message/rfc2822" will help us to get the raw MIME 
    delivered_events.each do |event| 
     response = RestClient::Request.execute method: :get , 
               url: event["storage"]["url"], 
               user: "api", password:"#{configuration.api_key}", 
               Accept: "message/rfc2822" 
     sent_emails.push(JSON.parse(response)) 
    end 
    sent_emails 
    end 

Welche dieser Helfer verwendet, um Ereignisse zu holen:

def self.get_events_for(email:, event_type: "delivered") 
    delivered_to_target = [] 
    response = RestClient.get "https://api:#{configuration.api_key}"\ 
    "@api.mailgun.net/v3/#{configuration.api_domain}/events", 
    :params => { 
     :"event" => event_type 
    } 

    all_delivered = JSON.parse(response)["items"] 

    all_delivered.each do |delivered| 
     if (delivered.has_key?("recipients") and delivered["recipients"].include?(email)) or 
     (delivered.has_key?("recipient") and delivered["recipient"].include?(email)) 
     delivered_to_target.push(delivered) 
     end 
    end 
    delivered_to_target 
    end 

Und hier in meinem spec Ich habe:

it 'can get the list of previously sent emails to an email address' do 

    allow(StudySoup).to receive(:get_events_for).with({email: email}) { 
     Array(TestHelpers::get_json(filename: 'spec/fixtures/events.json')) 
    } 

    allow(RestClient::Request).to receive(:execute).with(any_args){ 
     TestHelpers::get_json(filename: 'spec/fixtures/messages.json') 
    } 

    expect(StudySoup.get_messages_for(email: email)["subject"]).not_to be nil 
    end 

Allerdings als ich versuchte, rspec zu laufen, hat es immer folgende fail Spur:

1) StudySoup can get the list of previously sent emails to an email address 
    Failure/Error: url: event["storage"]["url"], 

    TypeError: 
     no implicit conversion of String into Integer 
    # ./lib/StudySoup.rb:51:in `[]' 
    # ./lib/StudySoup.rb:51:in `block in get_messages_for' 
    # ./lib/StudySoup.rb:49:in `each' 
    # ./lib/StudySoup.rb:49:in `get_messages_for' 
    # ./spec/StudySoup_spec.rb:86:in `block (2 levels) in <top (required)>' 

Ich dachte, ich die RestClient::Request.execute Methode Stub, so sollte es funktionieren, aber es kam nicht. Irgendwelche Ideen, wie ich diese Funktion richtig testen kann? Ich habe versucht, viele params Matcher wie alles(), Hash_including (: key => Wert) ... aber es hat immer noch nicht funktioniert.

Antwort

1

Sie haben tatsächlich die execute Methode ausgedruckt. Das bedeutet, dass rspec mit dieser Klasse fiedelt, sodass Versuche, execute aufzurufen, rspec Code anstelle der ursprünglichen Implementierung bereitgestellt haben. Insbesondere werden alle Argumente für diesen Aufruf als normal bewertet.

Ändern der Argument-Matcher, wie Sie versucht haben, ändert, ob rspec entscheidet, dass der Methodenaufruf mit einem der konfigurierten Stubs übereinstimmt, kann jedoch nicht vermeiden, dass die Auswertung event["storage"]["url"] eine Ausnahme auslöst.

Wenn Sie get_events_for stubbed zurückgegeben Sie ein Array von Arrays anstelle eines Arrays von Hashes: Arrayto_ary oder to_a auf seine Argumente aufruft, die Ihre Hash in ein Array von Schlüssel-Wert-Paare dreht, anstatt das Einwickeln der Hash in einem Array wie ich denke, du dachtest es getan.

+0

In der Datei events.json habe ich nur einen json Hash, also ist das Ergebnis meiner get_json ein Hash (ich habe das in einem separaten rb-Skript getestet). Normalerweise wird in der Produktion get_events_for ein Array von Hashes zurückgeben, also sollte ich get_json nach Array übertragen (ich habe auch versucht, den Cast zu entfernen, aber es hat auch nicht funktioniert) – YaphatS

+0

gibt es eine Möglichkeit, Event ["Speicher" auszugeben ] ["url"]? sowas wie event = double allow (event) .to receive (: []) ... – YaphatS

+0

Ah, das Problem ist, dass Array (foo) nicht das tut, was Sie denken - es ist nicht dasselbe wie [foo] –