Scrivere codice non è un esercizio di stile, o una gara, per vedere chi lo sa scrivere meglio, ma è piuttosto risolvere i problemi che i Clienti ci propongono, e per i quali chiedono il nostro supporto.
I metodi Agili, di cui il manifesto ne sintetizza i principi, hanno senza ombra di dubbio, contribuito notevolmente a rafforzare questo concetto. La vera domanda, però, da sviluppatore quale sono, e quali siamo, è sempre stata “sì bello, ma come lo applico?” in sintesi “show me the code!”.
Proprio cercando di restare fedele ai principi del manifesto di cui sopra, ormai tutte le Aziende cercano il confronto continuo con chi commissiona il software per verificare che ciò che stanno realizzando sia proprio ciò che è stato chiesto, e non qualcosa di simile. Una delle pratiche Agili, che più di qualiasi altra, mantiene saldo questo rapporto costruttivo fra Cliente e Fornitore, è proprio il Behavior-Driven Development, un approccio proposto da Dan North. Si tratta di scrivere dei test, ma non i classici Unit Test per la verifica della singola funzionalità, ma test che verifichino il comportamento del nostro sistema. Questa tipologia di test è particolarmente interessante perchè, generalmente, è comprensibile sia agli sviluppatori, ma anche agli uomini del business (stackholder, PO, etc.), grazie ad una sintassi (Gherkin) che è allo stesso tempo rigorosa e discorsiva. L’idea alla base del BDD è quella di rompere lo scenario da testare in tre sezioni
- given: rappresenta la pre-condizione esistente prima che vengano applicati i comportamenti desiderati al nostro sistema.
- when: questa è la sezione in cui applichiamo il comportamento desiderato.
- then/expected: in questa sezione testiamo se i cambiamenti apportati al nostro sistema sono esattamente quelli che ci saremmo aspettati. Se il sistema si comporta come desiderato
Inutile negare che questo approccio mi piace parecchio, nello sviluppo di applicazioni backend event-driven, come ad esempio applicazioni con il pattern CQRS/ES, lo applico sempre, e lo trovo di grande supporto. Sono così convinto del suo valore che mi sono chiesto se fosse possibile applicarlo anche lato frontend nello sviluppo di applicazioni con Blazor.
Ovviamente la risposta è si, ed infatti eccomi a raccontare com’è andata.
Prima di partire dobbiamo configurare l’ambiente di sviluppo installando l’estensione di SpecFlow. Per gli amanti di VisualStudio

Oppure, per coloro che utilizzano Rider

Stiamo parlando di frontend, di applicazioni che girano nel browser, quindi abbiamo bisogno di uno strumento che ci permetta di automatizzare le interazioni con il browser, e Selenium è ancora un ottimo candidato. Vi segnalo comunque anche questo post del grande Andrea Dottor in cui propone Playwright come alternativa. In ogni caso al browser non importa quale framework utilizziamo, basta che possa eseguire l’applicazione compilata!
Un’ultima configurazione prima di passare al codice. Una volta scritti i test, proprio perchè sono uno strumento comprensibile a tutti i membri del Team, sarebbe molto utile poter produrre della documentazione che ne certifichi la scrittura e l’esito. SpecFlow ha pensato anche a questo aspetto; ci basta installare un pacchetto NuGet all’interno del nostro ambiente di sviluppo, ed uno nella CLI

Questi pacchetti ci permetteranno di generare della documentazione HTML da poter condiviedere con tutti.
Show me the code!
Trovate tutto il codice relativo a questo articolo qui.
Prendiamo come esempio un’applicazione molto semplice con un microfrontend Pubs ed un microfrontend Produzione (per la creazione di applicazioni microfrontend potete leggere questo articolo, sempre sul nostro sito), di cui vogliamo testare alcuni comportamenti.
La prima cosa da fare è creare un progetto con il template che SpecFlow ci mette a disposizione dopo aver installato l’estensione di cui sopra.

Che ci genererà un progetto con questo aspetto:

Ora possiamo creare il primo test, partendo da uno scenario semplice. Il nostro Cliente desidera che quando l’utente del suo portale naviga sulla pagina dei Pubs, gli compaia una griglia che li mostri tutti. L’estensione installata ci consente di aggiungere una feature al nostro sistema

Che aggiungerà un file simile a questo al nostro progetto

Come possiamo vedere la scrittura utilizzando il linguaggio Gherkin è comprensibile a tutti, non serve essere degli sviluppatori per leggere questo test. L’estensione ci guida anche nella scrittura del codice necessario ad eseguire il test. Innanzitutto colorando il testo delle varie sezioni in maniera diversa se lo abbiamo già implementato, oppure no. Con la classica short-cut CTRL-F12 su ogni sezione l’IDE ci guiderà al codice, oppure ci proporrà di scriverne la struttura per noi. Gli step per l’esecuzione del codice si trovano nella cartella StepDefinitions del nostro progetto

Analizziamo le parti salienti. Nella sezione BeforeScenario viene instanziato il nostro oggetto browser, incaricato di hostare l’applicazione. Possiamo decidere se visualizzarlo durante l’esecuzione dei test, oppure tenerlo nascosto, il tuoo passando dalle options a disposizione. Altrettanto importante, dopo aver inizializzato il browser, è chiuderlo al termine di ogni test

Una volta impostato l’ambiente, troviamo le nostre sezione Given / When / Then, ossia i metodi che richiamano ciò che lo scenario descrive, ponendo le condizioni dello scenario stesso come decorator per i nostri metodi. In questo caso la condizione Given è semplice, ci chiede di navigare all’indirizzo del nostro sito, e lo stesso vale per il When per il quale vi rimando all’esempio allegato. Nulla di interessante per un dev.
Megli concentrarci sul Then

La libreria ci permette di permette di trovare elementi all’interno della pagina (la grglia in questo caso) e di verificare appunto che questi siano presenti. Primo test portato a casa!
Complichiamo lo scenario
Vogliamo testare che al momento del salvataggio di un nuovo ordine, l’utente abbia inserito il relativo numero di riferimento, ed in caso contrario venga visualizzato un errore
Feature: SalesOrderNumberIsMandatory
A short summary of the feature
@SalesOrderNumberIsMandatory
Scenario: User tries to save a sales order without a sales order number
Given User is on the sales order page
When User tries to save the sales order
Then User is shown an error message if the sales order number is missing
Tralasciando le sezioni ripetitive dell’implementazione, analizziamo il resto
[Given(@"User is on the sales order page")]
public void GivenUserIsOnTheSalesOrderPage()
{
Driver.Navigate().GoToUrl($"{Url}pubs");
Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
_addButton = Driver.FindElement(By.Id("add-button"));
_addButton.Click();
_saveButton = Driver.FindElement(By.Id("save-button"));
}
[When(@"User tries to save the sales order")]
public void WhenUserTriesToSaveTheSalesOrder()
{
_saveButton.Click();
Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
}
[Then(@"User is shown an error message if the sales order number is missing")]
public void ThenUserIsShownAnErrorMessageIfTheSalesOrderNumberIsMissing()
{
_alertMessage = Driver.FindElement(By.Id("alert-message"));
Assert.Equal("Order Number is Mandatory!", _alertMessage.Text);
}
Come possiamo vedere, la nostra libreria, oltre a permetterci di trovare elementi nella pagina ci permette di interagire con essi, come simulare il Click di un bottone. In altri esempi presenti nel codice trovere anche come interagire con le textbox per immettere testo nelle nostre pagine, ad esempio, e altri casi interessanti.
Conclusioni
Scrivere test è spesso considerato un costo aggiuntivo. Considerazione totalmente sbagliata a mio modesto avviso. Si pensa sempre che lo scopo del test sia, appunto, avere a disposizione degli strumenti automatici che verifichino che il nostro sistema faccia ciò per cui è stato progettato e scritto, ma questo è solo il side-effect di un sistema costruito partendo dai test. Il mantra dello sviluppo guidato dai test, sia esso TDD o BDD, è red-green-refactor e la parte più importante è proprio il red. E’ proprio il momento in cui sono davanti al file vuoto e devo scrivere il test per qualcosa che ancora non ho! Dovendo pensare a cosa testare prima, ancora di scriverlo, mi costringe a scriverlo nel miglior modo possibile, ossia a scrivere solo il codice necessario a passare il test, nulla di più, nulla di meno! Nessun spreco, solo l’indispensabile. Come sempre, se avete suggerimenti da condivedere, scrivetemi pure, sarò lieto di condiviedere ogni esperienza in merito.