Visualizzazione post con etichetta Android. Mostra tutti i post
Visualizzazione post con etichetta Android. Mostra tutti i post

giovedì 12 settembre 2013

Il DBB per il test della componente "Server" - parte 2


Prosecuzione del post sul BDD per il test del server

Il BDD - behavior-driven development (continua)

Definito lo scenario con cucumber, come abbiamo fatto nel post precedente, è necessario definire i test di validazione delle features, che si concentreranno sul "consumo" dei webservice e non sulla tecnica di programmazione.

I punti focali di questi test sono che:
  1. possiamo farli prima di iniziare a (o a far) codificare
  2. sono indipendenti dal linguaggio con cui sarà realizzato il progetto.
Per la definizione degli step possiamo partire dagli snippet generati automaticamente da cucumber (sul sito vi sono vari tutoriarl che illustrano come codificare gli step).
In questo caso, volendo scrivere un test di controllo su come un client esterno possa consumare i servizi esposti, non verrà verificata la logica dei modelli, ma il funzionamento dei controller. 

Ad esempio nel nostro case avremo:


Given(/^a user "(.*?)" with password "(.*?)"$/) do |user, password|
 @username=user
 @password= password
end

When(/^he logs whit username and password$/) do
  header 'Accept', 'application/json' 
  header 'Content-Type', 'application/json'
  params={username: @username, password: @password}
  post 'users/sign_in', params.to_json
  page = JSON.parse(last_response.body)
  @token=page["auth_token"]
  @token.should_not == nil
end

Then(/^he should navigate page "(.*?)" and see (\d+) records$/) do |arg1, arg2|
  get arg1, {auth_token: @token}
  page = JSON.parse(last_response.body)
  page.size.should == arg2.to_i
end
 
Then(/^he should navigate page "(.*?)"$/) do |arg1|
  get arg1, {auth_token: @token}
end

Then(/^he should see olny his documents$/) do 
  get "my_documents", {auth_token: @token}
  last_response.status.should == 200 #HTTP status OK
  page = JSON.parse(last_response.body)
  page.map{|u| u["user"]["customer_name"]}.compact.uniq.should include(@user.customer_name)
end

Then(/^he shouldn't navigate page "(.*?)"$/) do |arg1|
   get arg1, {auth_token: @token}
   last_response.status.should == 403 #HTTP status forbidden
end

Questo test verificherà - indipendentemente dalla modalità di realizzazione - che il nostro server risponda a: 
- un servizio di login
- un servizio di risposta agli indirizzi customers, operators, settings, documents, che verifichi il tocken ed il profilo dell'untente , eventualmente restituendo uno stato di fobidden e che restituisca una array di record
- un servizio denominato "my_documents"

Naturalmente alcuni di questi test, come ad esempio l'autenticazione con username e password, presuppongono che il sistema sia stato popolato. Basta predisporre un passo di popolazione dell'ambiante di test, attraverso una delle 2 modalità che preferiamo (ed in funzione di cosa dobbiamo testare):

A) utilizzo degli script di avvio di cucumber, in particolare dello svript env.rb, in cui, in questo caso ho aggiunto il blocco
    Before do
      User.create(:username=>"operator1", :password=>"test1234", :role=>"operator", :email=>"operator1@mail.local")#this code is run before each scenario
      User.create(:username=>"operator2", :password=>"test1234", :role=>"operator", :email=>"operator2@mail.local")#this code is run before each scenario
      User.create(:username=>"operator3", :password=>"test1234", :role=>"operator", :email=>"operator3@mail.local")#this code is run before each scenario
      cust1=User.create(:username=>"customer1", :password=>"test1234", :role=>"customer", :customer_name=>"azienda1", :email=>"customer1@mail.local")#this code is run before each scenario
      cust2=User.create(:username=>"customer2", :password=>"test1234", :role=>"customer", :customer_name=>"azienda2", :email=>"customer2@mail.local")#this code is run before each scenario
      cust1.documents.create(document_type: "F24_init")
      cust1.documents.create(document_type: "Bilancio_init")
      cust2.documents.create(document_type: "F24_init")
      cust2.documents.create(document_type: "Bilancio_init")
    end

B) scrittura di scenari di popolazione, che utilizzeremo per i test sui servizi.


Abbiamo quindi simulato - evitando di farlo manualmente ogni volta -
- l'apertura della finestra di login
- l'inserimento di user e password "amministrative"
- la navigazione (manuale, mancando al momento i link) di 4 pagine e il conteggio de record
- il logout
- l'inserimento di user e password "utente"
- la navigazione (manuale, mancando al momento i link) di 5 pagine e il conteggio de record

Considerando che al progredire di un progetto i dati da immettere per verificare quanto abbiamo codificato aumentano esponenzialmente... siamo ancora sicuri che scrivere test in questo modo sia una perdita di tempo?


lunedì 9 settembre 2013

Il DBB per il test della componente "Server" - parte 1


Prosecuzione del post sul paradigma Client/Server

Lo sviluppatore non testa ... falso! "auto-testa"

Come scritto sul post precedente, realizzare una componente server presuppone OBBLIGATORIAMENTE di investire delle risorse per il testing.

Ci sono vari modi di fare test, e per esperienza una volta che il codice viene scritto difficilmente si torna allo sviluppo del test.

Ma in realtà questo tempo viene già "sprecato". Facciamo un esempio.
Tipicamente lo sviluppo "agile" con ROR (o altri framework) prevedere che:
  1. si inizia a scrivere del codice, magari prendendo spunto da precendenti progetti o ricerche su google
  2. si avvia il server e si controlla se non si sono fatti errori di sintassi
  3. si avvia il browser e si naviga l'applicazione
  4. si compilano un po di dati
  5. si ricarica la pagina
  6. ci si imbatte in un errore
  7. trovato si vede sul log il punto sul sorgente che ha dato errore e si torna al punto 1

Quindi c'è già un tempo impiegato a di navigare, immettere dati, ricaricare pagine.

Inoltre più aumentano le funzionalità, maggiore è il tempo "perso" a caricare e ricaricare i dati.

Si pensi ad esempio a quante volte si ridigitano credenziali di accesso o testi di ricerca

Il BDD - behavior-driven development

Utilizzare correttamente i sistemi di BDD permettono
- di ottimizzare i tempi di sviluppo (riducendo i tempi di auto-test)
- di garantire la stabilità del codice
- di aumentare il livello di coinvolgimento del cliente e degli altri team

Nel nostro esempio, dovendo partire a sviluppare la componente server, si è partiti dalla definizione delle funzionalità (behavior) e degli scenari d'uso:

#encoding: utf-8
Feature: Login
  Per verificare che il login funzioni correttamente
  Come operatore devo poter accedere alle funzioni riservate
  Come cliente devo poter vedere solo i miei documenti
  Il sistema viene precaricato con 3 operatori, 2 utenti e 4 documenti
   
  Scenario: Login Operatore
    Given a user "operator1" with password "test1234"
    When he logs whit username and password
    Then he should navigate page "operators" and have 3 records 
    And  he should navigate page "customers" and have 2 records
    And  he should navigate page "settings"
    And  he should navigate page "documents" and have 4 records

  Scenario: Login Cliente
    Given a user "customer1" with password "test1234"
    When he logs whit username and password
    Then he should see olny his documents
    And  he shouldn't navigate page "documents" 
    And  he shouldn't navigate page "customers" 
    And  he shouldn't navigate page "users"
    And  he shouldn't navigate page "settings"

e ancora

#encoding: utf-8
Feature: Caricamento documenti
  Per verificare il corretto funzionamento dei documenti
  Come operatore dovrei essere in grado di caricare un nuovo tipo di documento ed   associarlo ad un cliente
  Come Cliente dovrei essere in grado di vedere i documenti a me associati e scaricarli
Il sistema viene precaricato con 3 operatori, 2 utenti e 4 documenti
Scenario: Caricamento documenti da operatore1
    Given a user "operator1" with password "test1234"
    When he logs whit username and password
    Then he should navigate page "customers"
    And he should navigate customer "azienda1"
    And he should upload an "F24" using "file1"
    And customer should have assigned an "F24"

  Scenario: Caricamento documenti da operatore2
    Given a user "operator2" with password "test1234"
    When he logs whit username and password
    Then he should navigate page "customers"
    And he should navigate customer "azienda2"
    And he should upload an "Bilancio" using "file2"
    And customer should have assigned an "Bilancio"

  Scenario: Accesso a documenti da cliente
    Given a user "customer1" with password "test1234"
    When he logs whit username and password
    Then he should have a list of documents that include an "F24_init"

Paradigma Client/Server anche per sviluppare applicazioni "semplici"? Perchè no?

Oggi ho iniziato a sviluppare una piccola applicazione - rigorosamente con Rails -  ad uso interno.

Nulla di complicato, anzi tutt'altro, ma mi sono chiesto se la sua semplicità fosse un buon motivo per non svilupparla "bene", ovvero per non dividere i livelli di logica di business e di presentazione.

Non è che le cose piccole siano per definizioni da fare male, anzi .... la semplicità (così ci insegna la UX) spesso è figlia di molto lavoro ed esperienza.

Veniamo quindi alla nostra applicazione.

Le funzioni richieste sono basilari, e dopo una prima fase di analisi sono riassumibili in:
- deve prevedere accessi profilati ed autenticati
- deve permettere la gestione di settings
- deve permettere la il caricamento di documenti con alcuni metadati (legati agli utenti ed ai setting)
- deve inviare delle notifiche a fronte del caricamento
- deve tracciare le azioni eseguite sul documento

Abbiamo quindi il modello principale DOCUMENT a cui sono funzionali il modello USER ed il modello SETTING

La prima applicazione gestirà la logica di business e le funzioni backend del sistema e sarà interrogabile solo tramite WebService

La seconda applicazione - che potrà anche essere client javascript - consumerà tali servizi e fornirà la User Interface all'utente, definendo la logica di presentazione

I vantaggi - a parte quelli puramente "accademici" - sono molteplici:

1) Possiamo demandare ad un'altro gruppo / persona lo sviluppo dell'interfaccia
2) Possiamo scrivere differenti interfacce per differenti device. Quindi realizzare da un client locale, compilato per la singola piattaforma, ad una webapp, ad un sito mobile
3) Il gruppo che si occupa delle interfacce utente NON POTRA' in alcun modo interferire con la logica di business
4) Nessun codice sarà condiviso tra i due gruppi e pertanto sarà effettivamente possibile DIMEZZARE i tempi di sviluppo (lo so non è vero.. ma passatemi la licenza), a patto di definire bene la struttura dei messaggi

Svantaggi:

1) senza una suite di test chi sviluppa il backend lavorerà alla cieca o dovrà fare dello sviluppo "a perdere".
2) senza una formalizzazione dei messaggi chi lavora al frontend sarà costretto a lavorare senza dati in modo statico

A mio parere questi non sono degli svantaggi, ma una evidente forzatura a costringere lo sviluppatore in termini di ciò che può essere TESTATO e non di ciò che può essere VISTO

domenica 28 ottobre 2012

Infografica: l'evoluzione degli smartphone

Leggendo questo post su ReadWrite mi sono imbattuto in questa infografica sull'evoluzione degli smartphone.

Mi ha fatto riflettere sul fatto che parliamo di oggetti che 30 anni fa non esistevano, ad ulteriore riprova di quanto sia difficile se non impossibile ragionare su investimenti a lunga scadenza in ambito informatico: probabilmente le tecnologie che oggi sono all'avanguardia non lo saranno più tra 3/4 anni, e saranno completamente sostituite tra 10 anni, e questo vuol dire che chi investe oggi deve necessariamente fare i conti con un rientro break-even point di 2/3 anni al massimo.

Mi ha fatto sorridere ricordare dei telefoni "waterproff" della ericsoon (qualcuno la ricorda più?)

Mi ha stupito  che la Android Inc sia stata fondata nel 2003 ... ed acquistata nel 205 da Google: alla fine anche loro hanno impiegato non meno di 7 anni ad emergere

Non sono proprio d'accordo con la conclusione (a meno che non si contino anche i sensori attivi): si sta affermando il "device unico" e alla fine molti dei dispositivi oggi esistenti verranno sostituiti o rimpiazzati da device sempre più intelligenti e sempre più connessi: il  paradigma client - server , applicato al binomio individuo - cloud sfruttando la capacità delle connessioni 3G e 4G, potrebbe essere una soluzione stabile ed a lungo termine.