2009-12-18 6 views
8

ich Sinatra App haben, die Seiten als schreibgeschützt oder editierbare dient je nachdem, ob der Benutzer angemeldet ist.Testing Controller Instanzvariablen mit Rack-:: Test und Sinatra

Der Regler eine Variable @can_edit setzt, dh Wird von den Ansichten verwendet, um Bearbeitungslinks zu verbergen/anzuzeigen. Wie kann ich den Wert @can_edit in meinen Tests testen? Ich habe keine Ahnung, wie ich unter Rack :: Test auf die aktuelle Instanz des Controllers zugreifen kann.

Ich benutze class_eval die logged_in? Methode in der Steuerung Stummel, aber ich habe auf die Überprüfung last_response.body für meine bearbeiten Links zu greifen, um festzustellen, ob @can_edit oder nicht festgelegt wurde.

Wie kann ich den Wert von @can_edit direkt testen?

Antwort

8

Leider glaube ich nicht, dass dies ohne Änderung von Rack :: Test möglich ist. Wenn Sie eine Anforderung bei Anwendungstests machen, Schärfen :: Test macht folgendes:

  1. die Anfrage auf eine Liste der letzten Anfragen fügt
  2. eine neue Instanz der Anwendung erstellt und ruft seine call Methode
  3. fügt Reaktion Ihrer Anwendung auf eine Liste der letzten Antworten

es ist einfach, die last_request und last_response, aber leider keine Informationen gespeichert über den Zustand Ihrer Anwendung zuzugreifen, während es runni ist ng. Wenn Sie daran interessiert sind, einen Rack :: Test-Patch zusammen zu hacken, beginnen Sie mit der Anzeige von rack-test/lib/rack/mock_session.rb in Zeile 30. Hier führt Rack :: Test Ihre Anwendung aus und erhält die standardmäßigen Rack-App-Rückgabewerte (Status, Header, Körper). Meine Vermutung ist, dass Sie auch Ihre Anwendung ändern müssen, um alle ihre Instanzvariablen zu sammeln und zugänglich zu machen.

In jedem Fall ist es am besten, auf Ergebnisse zu testen, nicht Implementierungsdetails. Wenn Sie sicherstellen möchten, dass ein Link Bearbeiten nicht sichtbar ist, Test für das Vorhandensein der Link Bearbeiten von DOM-ID:

assert last_response.body.match(/<a href="..." id="...">/) 
+0

"Es ist am besten, auf Ergebnisse zu testen, nicht Implementierungsdetails" Ich habe ähnliche Aussagen wie diese zuvor gesehen, und ich muss widersprechen. Wenn Sie 2 wollen, funktioniert 1 + 1 ganz gut, aber auch 1 + 2 + 10 - 11. Keine davon bedeutet, dass Ihre Anwendung "tatsächlich ordnungsgemäß funktioniert". – nowk

+1

Ich stimme Ihnen jedoch nicht völlig zu: Sagen wir, es gibt eine Methode, die falsch implementiert wird.Wenn die Methode in 100% der Fälle die richtige Antwort liefert (Sie können sich keinen Fall vorstellen, bei dem ein Fehler auftritt), ist die Implementierung wirklich "inkorrekt"? Ist es wichtig? Wenn Sie feststellen, dass Sie die Werte von Variablen in Methoden testen, verfügen Sie möglicherweise nicht über genügend Testfälle (Eingaben). Wenn Sie Variablen umbenennen oder die Implementierung der Anwendung ändern, ohne ihr Verhalten zu ändern, sollten Ihre Tests ohne Änderungen ausgeführt werden. Dies ist ein wichtiger Grund für die Verwendung von Tests an erster Stelle. –

+0

Ich denke, das Testen von @can_edit testet die Ausgabe des Controllers. Ich mag es nicht, es indirekt zu testen, indem ich die Ansicht überprüfe, was passiert, wenn @can_edit gesetzt wird. Das sollte ein anderer Test sein, nur für die Ansicht. – Brian

4

Es ist möglich, mit einem kleinen Hack. Die Instanzen der Sinatra-App sind nicht verfügbar, da sie beim Aufruf von Sinatra :: Base # erstellt werden. wie Alex erklärte. Dieser Hack bereitet eine Instanz auf die Zukunft vor und lässt sie beim nächsten Aufruf erfassen.

require 'something/to/be/required' 

class Sinatra::Base 
    @@prepared = nil 

    def self.onion_core 
    onion = prototype 
    loop do 
     onion = onion.instance_variable_get('@app') 
     return onion if onion.class == self || onion.nil? 
    end 
    end 

    def self.prepare_instance 
    @@prepared = onion_core 
    end 

    # Override 
    def call(env) 
    d = @@prepared || dup 
    @@prepared = nil 
    d.call!(env) 
    end 
end 

describe 'An Sinatra app' do 
    include Rack::Test::Methods 

    def app 
    Sinatra::Application 
    end 

    it 'prepares an app instance on ahead' do 
    app_instance = app.prepare_instance  
    get '/foo' 
    app_instance.instance_variable_get('@can_edit').should be_true 
    end 
end 

dachte ich, in erster Linie, diese Technik zu mock the instance that runs the current test aus.

+0

Das gibt nil app_instance für mich zurück. Wahrscheinlich änderte Sinatra seine Basisklasse. – gpavlidi

0

Heres eine unangenehme, aber praktikable Alternative

# app.rb - sets an instance variable for all routes 
before do 
    @foo = 'bar' 
end 

# spec.rb 
it 'sets an instance variable via before filter' do 
    my_app = MySinatraApplication 
    expected_value = nil 
    # define a fake route 
    my_app.get '/before-filter-test' do 
    # as previously stated, Sinatra app instance isn't avaiable until #call is performed 
    expected_value = @foo 
    end 
    my_app.new.call({ 
    'REQUEST_METHOD' => 'GET', 
    'PATH_INFO' => '/before-filter-test', 
    'rack.input' => StringIO.new 
    }) 
    expect(expected_value).to eq('bar') 
end 

Diese Sie gegen einen sinatra vor Filter und oder Zugriffsinstanzvariablen für die Basisanwendung erstellt testen können.