Workflow Foundation, Composite Activity e Unit Testing di WF
In un progetto che stiamo seguendo (nel quale è coinvolto anche
RoB), facciamo un pesante uso di WF. Siamo per ora molto soddisfatti del risultato e contenti di averci pensato (a WF intendo :-) ...). Abbiamo però incontrato un problema non banale, che ci ha fatto perdere diversi giorni per essere individuato e risolto. Per questo preferisco lasciarne traccia su questo blog.
In sostanza abbiamo diversi workflow che riutilizzano le stesse Activity custom, come è normale che sia in progetti che usano WF.
In particolare abbiamo creato delle custom composite activity, per utilizzare le nostre stesse activity custom in dei blocchi più complessi, tipicamente delle WhileActivity e dei Replicator, con anche una gestione sempre "fissa" delle eventuali eccezioni durante il flusso.
Questo ci consente di avere comportamenti uniformi tra i vari workflow, oltre ad una migliore mantenibilità del codice.
Il problema riscontrato è che queste composite activity custom, che sono scritte solo da codice, referenziano al loro interno delle Activity che hanno delle ActivityCondition (CodeCondition o RuleConditionReference). Nel nostro caso sono solo RuleConditionReference.
In fase di caricamento (durante la CreateWorkflow) e di validazione delle activity, il motore di WF cerca il riferimento al contenitore delle Rules a livello di RootActivity, ma nel nostro caso questo non è vero. Purtroppo il motore di WF non impedisce la definizione di Activity custom che ne contengono altre che a loro volta usano delle Rules, però in fase di load e di validation, si blocca con una bella NullReferenceException perché cerca la RuleDefinition a livello di RootActivity, non trovandola.
Nel nostro caso abbiamo aggirato il problema, però non è stato per nulla facile trovarne la causa, lo sa bene
Cristian che ci ha litigato per diversi giorni, lavorando di Reflector e debugger.
Questo problema sembra non manifestarsi per le composite disegnate dal designer, ma potrebbe capitare anche a voi di lavorare con composite da codice, quindi è meglio saperlo.
Un altro "problema" (diciamo così) che abbiamo riscontrato è il fatto che non è per nulla banale svolgere Unit Testing dei worfklow.
Infatti non è così semplice testare le singole Activity e ancor di più i flussi.
La strada che abbiamo scelto è stata di creare da codice dei TestMethod che creano dei "mini-workflow" con i quali eseguiamo le singole Activity. Sempre in questi TestMethod verifichiamo l'esito appoggiandoci ai componenti Biz, per controllare che il flusso abbia effettivamente fatto il suo lavoro.
Più semplice è stato invece testare le Rule usate nei workflow (dalle RuleConditionReference di prima) perché quelle alla fine sono dei normalissimi metodi di oggetti di business, quindi dei comuni TestMethod sono più che sufficienti.
Ora abbiamo la possibilità di fare UnitTesting di tutto il progetto, compresi i workflow, e questo non è affatto male per monitorare la correttezza di eventuali interventi di manutenzione/modifica del codice.
Come sempre quando si usano strumenti nuovi e tecnologie appena nate, c'è da trovare da soli soluzioni a problemi che con tecnologie più diffuse e consolidate, si trovano semplicemente con Google :-).