2015-09-04 16 views
5

Questa domanda riguarda l'avvio di un server di rotaie del progetto esterno da un ambiente rspec.Rspec: eseguire un server di guide esterne

Ci sono 2 progetti.

  • Il primo progetto funge da back office di amministrazione, è l'applicazione centrale in cui gli utenti interagiscono con le pagine Web. Io lo chiamo BackOffice
  • secondo progetto è un JSON API server che riceve i comandi dal Admin Back Office attraverso requests.I JSON chiamarlo ApiServer

sto cercando di testare l'interazione tra coloro API 2 progetti di rotaie e mi piacerebbe impostare rspec in modo che possa scrivere e mantenere i miei file spec nel progetto BackOffice. Queste specifiche avrebbero avviato un server di rotaie ApiServer e quindi avrebbero dovuto giocare per eseguire i test.

Il mio problema riguarda l'avvio del server di rotaie ApiServer. Dopo aver esaminato i file di inizializzazione delle app per i binari, ho pensato di dover aggiungere una richiesta a "config/environment".


Ma quando inserisco in BackOffice/spec/spec_helper.rb

require File.expand_path('../../../ApiServer/config/environment', __FILE__) 

ottengo l'errore

`initialize!': Application has been already initialized. (RuntimeError) 
# Backtrace to the file: 
# ApiServer/config/environment.rb 
# Line: 
# Rails.application.initialize! 

Ho anche provato a chiamare semplicemente quanto segue in apici inversi

`cd /api/path; bundle exec rails s -p 3002` 

ma ottenuto lo stesso tipo di errore


Poi ho preso ispirazione da codice sorgente Capybara, e ha richiesto il "ApiServer/applicazione", quindi sono in grado di creare un oggetto ApiServer.new, ma non appena ho chiama initialize! su di esso ho lo stesso messaggio.

Qualsiasi aiuto è molto apprezzato. Cheers

+0

https://github.com/rails/rails/blob/3e36db4406beea32772b1db1e9a16cc1e8aea14c/railties/lib/rails/application.rb#L58 Come puoi vedere qui, puoi solo inizializzare un binario senza sovrascrivere l'inizializzatore in 'Rails :: Application' –

+0

quindi se davvero pensi di volerlo fare, puoi sovrascrivere il metodo 'initialize' di' Rails :: Application' prima di richiedere il file 'environment' della seconda app –

+0

Thanks Yury. Ho appena dato un'occhiata al tuo suggerimento e non riesco ancora a capirlo, continuerò a guardare in questa direzione. O forse qualcosa può essere fatto in Capibara. – Benj

risposta

1

In realtà, la seconda app non è altro che un servizio esterno, che è meglio eseguire lo stub per i test.

C'è un bell'articolo dal thoughtbot sull'utilizzo vcr gemma per deridere servizi Web esterni:

https://robots.thoughtbot.com/how-to-stub-external-services-in-tests

+0

Grazie per la tua risposta. Ho già coperto entrambe le estremità dell'API con test stub. Non sto chiedendo se dovrei, sto chiedendo come farlo. – Benj

+0

In realtà ti suggerisco di evitare di fare richieste reali alla seconda app nei tuoi test e di bloccare la risposta della seconda app per i test di interazione. Perché altrimenti devi anche creare alcuni dati di test nella tua app api, e dovrai farlo dai test della tua applicazione di backoffice. –

+0

Penso che una buona pratica sarebbe scrivere un gemma client API, che avrebbe i propri test e un server fittizio (sinatra per esempio) per i test, che puoi includere nel tuo gemfile dell'applicazione 'backoffice', e avvia il server fittizio lì nel 'test_helper'. –

1

obbligatorio "non farlo a meno che non si ha realmente bisogno di".

Tuttavia, dal momento che sembra si sa che cosa avete bisogno:

Risposta breve:

È necessario isolare sia di applicazione in ambiente di sistema e lanciare da lì utilizzando la sintassi system-chiamate.

Risposta lunga:

quello che stai cercando di fare è di eseguire due applicazioni Rails nello stesso ambiente. Poiché entrambi sono applicazioni di Rails, condividono molti nomi comuni. Eseguirli termina con il nome scontro, che stai vivendo. La tua impressione di provare i back ticks semplici è stata buona, purtroppo sei andato con un bundler nell'ambiente già esistente, che si scontra anche.

Quello che devi fare per farlo funzionare è isolare correttamente (in termini di codice, non in termini di rete i.e. livello di comunicazione) l'applicazione e quindi eseguire launcher da rspec. Ci sono diversi modi, si potrebbe:

  • controllo di processo Usa Rubino (Controllare questo graph, si potrebbe provare a combinare con livello di sistema exec)
  • eseguito come demone da operativo a livello di sistema (init.d, ecc)
  • Incapsula in VM o uno degli involucri (Virtualbox, Vagrant, etc.)
  • impazzire e inserire il codice sulla macchina separata e controllare in remoto (Puppet, Ansible, ecc)

Una volta lì, puoi semplicemente eseguire il programma di avvio (ad es. daemon init script o genera nuovi processi in un ambiente isolato) da RSpec e il gioco è fatto.

Scegliere il modo in cui andare dipende molto dal proprio ambiente. Esegui OSX, Linux, Windows? Stai usando Docker? Gestisci le librerie Ruby attraverso cose come RVM? Cose come questa.

+0

Grazie per la tua risposta, ho provato questa direzione ma non ho esperienza in questo dominio e non ho avuto successo isolare gli ambienti (provato con 'fork' senza successo), forse ho bisogno di un po 'più di aiuto per trovare esattamente come farlo. Sto usando linux e rbenv. Preferisco rimanere locale se possibile, quindi non dovrò distribuire l'ApiServer per ogni bit di test. – Benj

+0

Personalmente per ambienti complessi o per quelli che non mi piacciono le impostazioni (come l'installazione di PHP/Apache globale nella workstation) di solito vado con [Vagrant] (https://www.vagrantup.com/). Secondo me è facile da configurare e funziona davvero bene. – XLII

+0

Vagrant non è gratuito. è un no go per me. Preferirei optare per una soluzione basata sul controllo del processo di ruby. Seguendo il grafico che hai linkato andrei su IO.popen. Ti piacerebbe scrivere un esempio di codice per me? – Benj

1

Generalmente è una cattiva idea richiedere l'avvio di un altro servizio/applicazione per far passare i test dell'unità. Questo tipo di interazione viene in genere verificato da risposte mocking o vcring o creando test di ambiente che vengono eseguiti su server distribuiti. L'avvio di un altro server è al di fuori dell'ambito di rspec e in generale, come hai scoperto, causerà un sacco di mal di testa da configurare e mantenere.

Tuttavia, se hai intenzione di avere questi progetti di binari strettamente accoppiati e vuoi che condividano le risorse, ti suggerisco di investigare su Rails Engines. Per fare ciò è necessaria una notevole quantità di lavoro, ma i vantaggi possono essere piuttosto elevati in quanto il codice condividerà un repository e avrà accesso alle reciproche capacità, mantenendo l'isolamento delle applicazioni.

I motori creano efficacemente un'applicazione di rotaia all'interno di un'altra applicazione di rotaie. Ogni applicazione ha il proprio spazio dei nomi e alcune protezioni isolanti per impedire la contaminazione delle app cross. Se disponi di molti motori, diventa ideale avere un'applicazione di shell shell con funzionalità minime che servono ciascun motore su un percorso/spazio dei nomi diverso.

Per prima cosa è necessario creare un alloggiamento per il nuovo motore api.

$ rails plugin new apiserver --mountable

Questo vi fornirà lib/apiserver/engine.rb così come tutte le altre impalcature è necessario eseguire il vostro API come un motore. Noterai inoltre che config/routes.rb ha ora un percorso per il tuo motore. Puoi copiare i percorsi esistenti in questo modo per fornire un percorso percorso per il tuo motore.Tutti i modelli esistenti dovranno essere spostati nello spazio dei nomi e sarà necessario migrare qualsiasi tabella associata alla nuova convenzione di denominazione. Avrai anche alcune modifiche personalizzate a seconda dell'applicazione e di ciò che devi copiare sul motore, tuttavia la guida delle guide ti guida attraverso queste modifiche (non le enumereremo tutte qui).

Ci è voluta una collega circa una settimana di lavoro per ottenere un motore complicato copiato in un altro server di rotaie complicato mentre lo sviluppo su entrambe le app stava avvenendo e conservando la cronologia del controllo della versione. Un'app più semplice - come un servizio solo API - Immagino che sarebbe più veloce da stabilire.

Ciò che questo ti dà è un altro ambito di namespace nella root dell'applicazione. È possibile modificare questa configurazione mentre si aggiungono più motori e codice condiviso per adattarsi a varie altre strutture di directory che hanno più senso.

app 
    models 
    ... 
apiserver 
    app 
     ... 

E una volta che hai spostato il codice nel motore, è possibile testare contro i router del motore:

require "rails_helper" 

describe APIServer::UsersController do 
    routes { APIServer::Engine.routes } 

    it "routes to the list of all users" do 
    expect(:get => users_path). 
     to route_to(:controller => "apiserver/users", :action => "index") 
    end 
end 

si dovrebbe essere in grado di mescolare e abbinare rotte da entrambi i servizi e ottenere cross- test delle applicazioni eseguiti senza avviare un'app Rails separata e senza richiedere un ambiente di integrazione per il passaggio delle specifiche.

Task rabbit ha un great blog su come generare un'applicazione di rota come riferimento. Si immergono in ciò che cosa fare e cosa no-to-fare in enginizing e andare in profondità più di quanto possa essere facilmente trascritto in un post SO. Suggerirei di seguire la loro procedura per prendere decisioni sul motore, anche se non è certamente necessario per avviare correttamente il tuo server API.

Problemi correlati