2005/12/18

Passi di UnitTest

Allora. Oggi ho deciso di mettere un po' di test al WorklistController.py che ahime' ne ha molti meno di quelli che dovrebbe avere. Sono partito dal codice di questo metodo, il primo che ho trovato che non veniva esplicitamente testato.


def actionShowDocument(self, instance_id, index, REQUEST):
""" """
instance = self.getOpenflow().getInstance(instance_id)
registration_id = self.getCore().getRegistrationId(instance)
if registration_id:
registration = self.getRegistrations().findLatestVersionById(registration_id)
else:
registration = self.getRegistrations().getInstanceRegistration(instance)
document = registration.getDocuments()[index]
return document.download(REQUEST)


Naturalmente, questo vuol dire dover creare un bel po' di mock per far funzionare il tutto.
La cosa che mi ha colpito è stato il fatto che dovessi chedere a Core di prendere il registration_id da una istanza: perché l'istanza non doveva saperlo? Sono quindi andato nel codice di Core.py, nella classe Core, ed ecco il codice del metodo in questione:


def getRegistrationId(self, instance):
if instance.begin_process_id in ('ModifyIncomingRegistrationProcess',
'ModifyOutgoingRegistrationProcess'):
return instance.getProtocolData().originalRegistrationId()
else:
return instance.getRegistrationId()


E' evidente che questo è un refactoring rimasto a mezzo. Infatti, dovrei:
  1. rinominare questo metodo
  2. spostarlo nella gerarchia dei RegistrationInstance
  3. implementarlo nelle sottoclassi

Visto che mi sembra giusto farlo, lo faccio subito! Dopo questo commit, andrò a riprendere il test della classe in questione.

2005/12/09

Riprendiamo a pubblicare su Note Notturne

Visto che devo lavorare un po' di notte, almeno aggiorniamo anche il blog, così forse mi faccio compagnia da solo.

Cosa c'è da fare stasera? Abbiamo iniziato una storia che dice:

Collegamento registrazioni: quando modifico una registrazione i collegamenti devono rimanere quelli della registrazione precedente.


In altre parole, in PAFlow è possibile modificare le registrazioni mantenendo traccia delle modifiche fatte. E' anche possibile collegare tra di loro le registrazioni. Purtroppo, però, in questo momento, quando una registrazione viene modificata i collegamenti con le altre registrazioni scompaiono. In effetti, non vengono cancellati, ma non sono più rintracciati come tali.

Da dove nasce questo problema? Bisogna guardare a come sono organizzate le registrazioni sul database. Ad ogni registrazione corrispondono una o più righe della tabella registrazioni, una per ogni versione della registrazione stessa. Ogni riga ha un identificativo di riga (id_registrazione) che identifica univocamente la riga. Ogni registrazione quindi ha più di un id_registrazione associato.

Le registrazioni sono collegate tra di loro tramite la tabella registration_link, nella quale sono memorizzati due id_registrazione. E qui avviene il problema: quando c'è una modifica, viene generata una nuova riga per la registrazione, e quindi un nuovo id_registrazione. Quindi, i collegamenti precedenti non sono più rintracciabili.

La soluzione che abbiamo pensato di adottare parte dalla seguente considerazione: le modifiche alle registrazioni non modificano i collegamenti esistenti. Quindi, abbiamo deciso di inserire nella tabella registration_link non l'id_registrazione corrente, ma quello del primo inserimento di quella registrazione. Corrispondentemente, useremo tale id_registrazione quando dovremo fare le ricerche. Al lavoro, dunque!


2005/08/17

Di nuovo al lavoro su PAFlow

Ok, è finita la pausa pranzo. Adesso ho un caffé, una storia da realizzare, un cronometro carico. La storia di oggi riguarda rimettere le mani nella gestione della firma digitale di PAFlow. Cerchiamo prima di tutto di capire qual è il primo test che devo scrivere per mettere in piedi quello che devo mettere in piedi.

I test sul DigitalSignController per ora funzionano: 8 test che girano tutti quanti. Adesso, visto che nel DigitalSignController sto assumendo che il PADocument implementi una nuova interfaccia (getReadOnly()), devo fare i test per controllare che la implementi davvero.

Nota a parte, devo anche ricordarmi di rendere quella parte un'interfaccia, in modo da evitare che ci sia un disallineamento tra il DigitalSignController e il PADocument, visto che il test del primo è fatto con un mock.

Metodi che spariscono (!)

E' buffo trovarsi a lavorare con il codice e ogni tanto trovare che un metodo che ci dovrebbe essere è sparito. Ma è quello che mi è appena successo: il metodo modifyMeasure del package PAFlowAccounting non c'è: viene invocato da PAFlow, ma non c'è in PAFlowAccounting.

Ho pensato: "E' stato fatto un refactoring, e quel metodo è sparito!"

Allora, per trovare dove si trovava, ho provato a guardare nel nostro CVS... ma nulla!

Questa è una di quelle cose che all'univesità non ti spiegano :(

2005/06/28

Legge di Demeter

Ecco uno degli aspetti della OOP che ancora mi mancano. Ho provato a dare una letta ad un articolo, poi ne ho discusso sul gruppo di extremeprogramming-it, in cui mi hanno dato un altro articolo da leggere.

Il problema è l'applicazione di questi aspetti al Metamapper in PAFlow. Il Metamapper è il nostro modo per rendere esplicite le dipendenze che derivano dall'Acquisition di PAFlow. In pratica, il Metamapper esporta tutti i metodi necessari a raggiungere tutti i tool (come odio questo termine!) di cui è fatto PAFlow.

E' quindi molto naturale in PAFlow vedere del codice del tipo:

charge = self.getMembershipManager().getLoggedCharge()

dove getMembershipManager() mi ritorna appunto il tool MembershipManager. Ora mi leggo anche il nuovo articolo, e poi vedo cosa fare.

2005/06/26

Automazione della creazione dei Mock

Finalmente sono riuscito a mettere la creazione di buona parte dei Mock di PAFlow direttamente all'interno del nostro TestCase base, invece di dover esplicitamente importare i metodi e crearli. In pratica, prima si doveva fare:

from Mock import manage_addMockCounter

class MyTest(ZopeTestCase.ZopeTestCase):

def testOne(self):
manage_addMockCounter(self.app)
...

ora invece:

class MyTest(AbstractLocalizedTestCase):

def testOne(self):
self._addMockCounter()


Il passo successivo è fare in modo che nessun test debba più dipendere da Mock, in modo che poi posso spostare AbstractLocalizedTestCase direttamente dentro Mock.

2005/06/25

Una a zero per il Vaticano

Ecco una visione dell'ultimo referendum svoltosi in Italia, visto dall'altra parte della Manica.

Nuova struttura delle notifiche

Finalmente sono riuscito a fare il commit delle notifiche, dopo averci lavorato, di qui e di lì, più di una settimana. Non sono sicuro di non aver introdotto qualche bug, anche se tutti i test di unità girano... tuttavia, continuare a tenermelo in pancia era il modo migliore per evitare che questi bug uscissero fuori.

Ora, se avessi anche il tempo di scrivere come sono strutturate le nuove cose...