2013-05-21 14 views
7

La mia prima domanda riguardante Ruby. Sto provando a testare l'interazione di EventMachine all'interno del ciclo di Reactor: immagino possa essere classificato come test "funzionale".Ruby EventMachine testing

Dire che ho due classi: un server e un client. E voglio testare entrambe le parti: devo essere sicuro della loro interazione.

Server:

require 'singleton' 

class EchoServer < EM::Connection 
    include EM::Protocols::LineProtocol 

    def post_init 
    puts "-- someone connected to the echo server!" 
    end 

    def receive_data data 
    send_data ">>>you sent: #{data}" 
    close_connection if data =~ /quit/i 
    end 

    def unbind 
    puts "-- someone disconnected from the echo server!" 
    end 
end 

Cliente:

class EchoClient < EM::Connection 
    include EM::Protocols::LineProtocol 

    def post_init 
    send_data "Hello" 
    end 

    def receive_data(data) 
    @message = data 
    p data 
    end 

    def unbind 
    puts "-- someone disconnected from the echo server!" 
    end 
end 

Così, ho provato diversi approcci e si avvicinò con niente.

La domanda fondamentale è - potrei testare in qualche modo il mio codice con RSpec, usando should_recive?

Il parametro EventMachine deve essere una classe o un modulo, quindi non è possibile inviare codice istanziato/deriso all'interno. Destra?

Qualcosa di simile?

describe 'simple rspec test' do 
    it 'should pass the test' do 
    EventMachine.run { 
     EventMachine::start_server "127.0.0.1", 8081, EchoServer 
     puts 'running echo server on 8081' 

     EchoServer.should_receive(:receive_data) 

     EventMachine.connect '127.0.0.1', 8081, EchoClient 

     EventMachine.add_timer 1 do 
     puts 'Second passed. Stop loop.' 
     EventMachine.stop_event_loop 
     end 
    } 
    end 
end 

E, se no, come lo faresti con EM :: SpecHelper? Ho questo codice che lo usa e non riesco a capire cosa sto facendo male.

describe 'when server is run and client sends data' do 
    include EM::SpecHelper 

    default_timeout 2 

    def start_server 
    EM.start_server('0.0.0.0', 12345) { |ws| 
     yield ws if block_given? 
    } 
    end 

    def start_client 
    client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient) 
    yield client if block_given? 
    return client 
    end 

    describe "examples from the spec" do 
    it "should accept a single-frame text message" do 
     em { 
     start_server 

     start_client { |client| 
      client.onopen { 
      client.send_data("\x04\x05Hello") 
      } 
     } 
     } 
    end 
    end 
end 

Provato un sacco di variazioni di questi test e non riesco proprio a capirlo. Sono sicuro che mi manca qualcosa qui ...

Grazie per il vostro aiuto.

risposta

4

La soluzione più semplice che mi viene in mente è quello di cambiare questo:

EchoServer.should_receive(:receive_data) 

A tal:

EchoServer.any_instance.should_receive(:receive_data) 

Dal EM si aspetta una classe per avviare un server, quanto sopra any_instance trucco farà si aspetti che ogni istanza di quella classe riceva quel metodo.

L'esempio di EMSpecHelper (pur essendo ufficiale/standard) è piuttosto contorto, preferisco attenermi alla prima rspec e usare any_instance, solo per ragioni di semplicità.

+1

Funziona. Una cosa da tenere a mente è che should_recive stub il metodo, quindi agisce come se non ci fosse nulla nel metodo. Grazie. – pfh

+0

http://axonflux.com/rspecs-shouldreceive-doesnt-ac – pfh

+1

Sì, RSpec supporta anche [chiamando nuovamente il metodo originale] (https://www.relishapp.com/rspec/rspec-mocks/v/2- 12/docs/message-expectations/calling-the-original-method) dalla v2.12. – Subhas