Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Migliorare i test in Ruby con ShouldA

Un'estensione di TestUnit per scrivere con rapidità test molto facili da interpretare
Un'estensione di TestUnit per scrivere con rapidità test molto facili da interpretare
Link copiato negli appunti

Molto spesso sentiamo parlare di Test Driven Development (TDD), ma non altrettanto spesso vediamo applicare questo approccio durante la fase di sviluppo del software.

Tra le varie cause e "motivazioni" quella che sentiamo più spesso ripetere è attribuibile alla mancanza di tempo, mancanza di tempo per un'attività - vogliamo ribadirlo - necessaria tanto quanto il codice stesso per il corretto funzionamento dell'applicazione che si vuole sviluppare.

Ruby, in RubyOnRails in particolare, offre le "consuete" librerie TestUnit per aiutarci a scrivere i test. In questo articolo esaminiamo ShouldA, un'interessante gemma che, estendendo TestUnit ci permette di scrivere dei test molto leggibili, e con relativa semplicità.

Un esempio per "stuzzicare" la curiosità, questo script di test (in Rails):

# test "classico"
class PostTest < ActiveSupport::TestCase

  def setup
    @p = posts(:one)
  end
		
  def test_should_have_valid_title
    assert @p.valid?

    # il titolo non può essere nil		
    @p.title = nil
    assert ! @p.valid?

    # il titolo non può essere vuoto
    @p.title = ''
    assert ! @p.valid?
  end
end

è equivalente a questo:

# con "shoulda"
class PostTest < ActiveSupport::TestCase
  context "A post instance" do
    setup do
      @p = posts(:one)
    end
			
    should_require_attributes :title
  end
end

Come possiamo vedere, utilizzando Shoulda è possibile scrivere dei test molto più concisi grazie all'uso delle macro che la gemma ci mette a disposizione. Ma l'aspetto più importante, e quello meno percepito in prima battuta, è il fatto che abbiamo una documentazione eseguibile del comportamento del nostro sistema.

Inoltre, Shoulda è perfettamente integrato con TestUnit, quindi possiamo tranquillamente continuare a scrivere i nostri test nella maniera "classica" (ovvero con metodi il cui nome inizia con 'test_'), ovvero possiamo estendere i nostri test man mano che prendiamo confidenza con ShouldA.

Installazione

A questo punto dovremmo essere abbastanza incuriositi per voler provare la gemma di persona. Prima di andare avanti, quindi, installiamo Shoulda:

$ sudo gem install shoulda

Anche come plugin all'interno della nostra applicazione Rails:

$ ruby script/plugin install git://github.com/thoughtbot/shoulda.git

Uso

Riprendiamo l'esempio precedente:

class PostTest < ActiveSupport::TestCase
  context "A post instance" do
    setup do
      @p = posts(:one)
    end
		
    should_require_attributes :title

    should "have some comment(s)" do
      assert @p.comments.size >= 0
    end
  end
end

Ogni "test" viene esplicitato con il metodo should che prende come parametri una stringa (che cosa fa il test) ed un blocco (il test vero e proprio). All'interno di should si utilizzano le consuete asserzioni fatte con tutte le variati di assert.

La prima cosa da introdurre è il concetto di contesto dell'oggetto (un model in questo caso) che vogliamo testare. Molto spesso la leggibilità dei test in TestUnit peggiora con l'aumentare dei contesti (situazioni) che circostanziano i nostri oggetti. Ad esempio, potremmo voler testare il comportamento del modello Post quando si tratta di un nuovo oggetto (quindi ancora vuoto), quando non ha commenti, quando non è associato ad alcun tag, e così via.

Per gestire più facilmente queste situazioni ShouldA utilizza il metodo context, che definisce - appunto - un contesto per i modelli oggetto del test.

Ogni context può contenere un metodo setup che inizializza l'oggetto, contestualizzando le sue proprietà (attributi e relazioni).

La cosa più interessante è che è possibile annidare più contesti per poter "specializzare" le caratteristiche dell'oggetto del test (es: un post, un post valido, un post valido con commenti, ...). Va notato che non è necessario, sebbene utile, definire un contesto. Vediamo un esempio:

class PostTest < ActiveSupport::TestCase
  
  context "A post instance" do
    setup do
      @p = posts(:one)
    end

    should "have a valid body" do
      assert_not_nil @p.body
    end
    
    # specializziamo il contesto: un post senza commento/i
    context "without comments" do
      setup do
        @p.comments.delete_all
        @p.save
      end
    
    should "not have comments attached" do
      assert @p.comments.size == 0
    end
  end

  # torniamo al contesto "padre"
  should "attach a comment to itself" do
    @c = Comment.create :content => 'put some word here'
    comment_count = @p.comments.size
    @p.comments << @c
    @p.save
    
    assert @p.comments.size == comment_count + 1
  end
end

Macro per testare i modelli

Un test linere, semplice, scorrevole da leggere (e da scrivere!) rappresenta una risorsa preziosa per il programmatore: meno si scrive e meno errori si possono commettere. Per questo motivo sono presenti una serie di utili macro per testare i modelli in Rails, vediamole nel nostro esempio del Post:

class PostTest < ActiveSupport::TestCase
  load_all_fixtures
  
  should_belong_to :user
  should_have_many :comments

  should_require_unique_attributes :title
  should_require_attributes :body
  should_only_allow_numeric_values_for :rating
  should_ensure_value_in_range :rating, 1..5
end

Macro per testare i controller

Ovviamente è possibile testare anche i controller. Vediamo l'uso di alcune macro apposite:

class PostsControllerTest < ActionController::TestCase
	
  context "on GET to :show for 1st post" do
    setup do
      get :show, :id => post(:one)
    end

    should_respond_with :success
    should_assign_to :post
		should_render_template :show
		should_not_set_the_flash
	end
end

Come possiamo vedere, con una sola linea di codice definiamo un test e la sua asserzione implicita (es: should_assign_to :post), a tutto vantaggio della leggibilità.

Sono anche presenti comode macro per il testing dell'interfaccia RESTful dei controller, sebbene abbiano ancora bisogno di qualche ritocco per funzionare con Rails 2.1.0 è consigliabile darci un'occhiata.

Conclusioni

Scrivere test può essere considerato un'attività noiosa e "collaterale", ma se cambiamo punto di vista ci accorgiamo che è invece estramemente importante (e utile!) descrivere cosa deve fare la nostra applicazione prima di scrivere come debba farlo. E se riusciamo ad alleggerire questo processo non avremo che vantaggi.

Riteniamo la community di Ruby (e di riflesso, quella di Rails) una delle più attive, pertanto assistiamo alla nascita quasi quotidiana di interessanti "gemme". Per non perdersi in questo immenso mare abbiamo piacere di segnalare le sperimentazioni che effettuiamo, sperando di "solleticare" sempre l'attenzione.

Ti consigliamo anche