Al recente Xamarin Day di Roma l’MVP Massimo Bonanni ci ha parlato dello Xamarin UITest, framework basato su Calabash per la scrittura e l’automazione di test di accettazione nel mondo dello sviluppo mobile.
Niente di nuovo sotto il sole, se non che in precedenza mi ero fatto ingannare troppo facilmente dall’apparentemente elevato costo del servizio in cloud e non avevo approfondito.
Detto che su GitHub ci sono molti esempi di utilizzo, e che io stesso in un progetto al lavoro ho preso “fortemente spunto” dall’app sviluppata per Xamarin Evolve 2016, riporto qui un mio piccolo esperimento fatto con un’applicazione sviluppata in Titanium. Ebbene sì, il framework è stato sviluppato dal team di Xamarin, ma può essere usato per automatizzare il processo di test su ogni applicazione mobile per Android e iOS. Per Windows non ancora, e la cosa può far sorridere considerato chi è il nuovo padrone di Xamarin, ma magari un giorno colmeranno la lacuna.
Per intenderci, funziona con tutte le tecnologie, ma ha senso usarlo soltanto con quelle che renderizzano componenti nativi: Android, iOS, Xamarin, Titanium, React Native, Native Script, … con i framework ibridi basati su Cordova/Phonegap questo approccio è sbagliato perché tutta l’applicazione gira all’interno di una webview.
Esperimento con Appcelerator Titanium
Quello sopra è l’albero degli elementi in una delle maschere dell’applicazione, così come Titanium l’ha generato a runtime. Gli elementi ci sono tutti, ma scriverci sopra dei test non è sempre banale perché non sempre ci sono degli id a cui poter fare riferimento e a volte bisogna ripiegare sul contenuto testuale. Mmmmm.
Quando si crea un progetto di tipo Xamarin.UITest Xamarin Studio genera in automatico una coppia di file, l’AppInitializer.cs e il Tests.cs. Naturalmente saremo poi liberi di modificare la struttura del nostro progetto come preferiamo (vedi l’app di Xamarin Evolve), ma in quei due file ci sono comunque tutti gli elementi di cui abbiamo bisogno per partire.
public class AppInitializer { public static IApp StartApp(Platform platform) { if (platform == Platform.Android) { return ConfigureApp .Android .ApkFile ("/Users/m.piccotti/src/ti_eatevolution/build/android/bin/Eat Evolution.apk") .EnableLocalScreenshots() .StartApp(); } return ConfigureApp .iOS //.AppBundle ("../../../iOS/bin/iPhoneSimulator/Debug/XamarinForms.iOS.app") .StartApp(); } }
[TestFixture(Platform.Android)] //[TestFixture(Platform.iOS)] public class Tests { IApp app; Platform platform; public Tests(Platform platform) { this.platform = platform; } [SetUp] public void BeforeEachTest() { app = AppInitializer.StartApp(platform); } [Test] public void AppWorks() { //app.Repl(); Func<AppQuery, AppQuery> title = (arg) => arg.Marked("Eat Evolution"); Func<AppQuery, AppQuery> barFofoGarden = (arg) => arg.Marked("Bar Fofo Garden"); Func<AppQuery, AppQuery> filtersButton = (arg) => arg.Class("ActionMenuItemView").Marked("Filters"); // 1 - info page app.WaitForElement(title); app.Screenshot("1 - info page"); Assert.IsNotNull(app.Query("JOIN US OR RECOMMEND").First().Text); app.TapCoordinates(100, 300); // 2 - list app.WaitForElement(barFofoGarden); app.Screenshot("2 - list"); app.Tap(barFofoGarden); // 3 - Fofo Garden detail app.WaitForElement(barFofoGarden); app.Screenshot("3 - Fofo Garden detail"); Assert.IsNotNull(app.Query("Bar Fofo Garden").First().Text); app.TapCoordinates(100, 100); app.WaitForElement(barFofoGarden); app.Tap(filtersButton); // 4 - filters screen app.WaitForElement(x => x.Marked("Confirm")); app.Screenshot("4 - filters screen"); Assert.IsNotNull(app.Query("Confirm").First().Text); Assert.IsNotNull(app.Query("Cancel").First().Text); app.Back(); } }
Ora… chi è un po’ pratico di test automatici di unità potrebbe rimanere inorridito al vedere quell’unico metodo AppWorks; certo sarebbe bello se ogni asserzione potesse essere verificata isolatamente, il problema è che questi test sono più lenti di quanto si possa immaginare, e i servizi cloud si pagano a ore. In sostanza entro certi limiti può aver senso anche una robaccia come quella sopra.
Per la cronaca quelle sotto sono le schermate catturate dal test.
Giusto un giretto tra le altre piattaforme
Che tutto avrebbe funzionato anche con le altre tecnologie concorrenti di Xamarin e Titanium non avevo dubbi, ma un giro di prova ho preferito farlo comunque. Sotto potete vedere i miei esperimenti fatti con le applicazioni demo delle varie piattaforme.
Per qualche ragione che non ho avuto voglia di approfondire con React Native l’applicazione è esplosa, come se il bridge tra l’applicazione di test e quella da testare non abbia funzionato. Il comando tree
richiamato con il repl (strumento utilizzabile da cli) ha visualizzato comunque l’albero degli elementi della schermata rossa.
Il tentativo con Ionic 2 l’ho fatto solo a scopo didattico, per vedere la famosa WebView. Teoricamente si può interagire con l’applicazione a furia di TapCoordinates, ma il test risultante sarebbe così fragile che non ha proprio senso perderci tempo. Per le applicazioni ibride basate su html tanto vale usare Protractor.
Conclusioni
Xamarin.UITest è una figata.
PRO:
- È possibile interagire con il dispositivo mentre il test automatico è in atto, sia fisicamente che attraverso il repl
- Con il comando tree da riga di comando si può visualizzare la struttura reale della propria applicazione così com’è stata renderizzata sul dispositivo, cosa che può tornare molto utile
- Funziona su Android e iOS.
- Con Xamarin Test Recorder si può registrare il proprio test andando poi a modificarne il codice
- Il test in cloud è utile non solo per testare automaticamente su molti dispositivi diversi, ma anche per fare test specifici quando ci vengono segnalati dei bug su un dispositivo particolare che non abbiamo a disposizione
- L’interfaccia web dei test in cloud è spaziale, ci da un sacco di informazioni anche sulle performance ed è possibile fare degli screenshot mirati in presenza di errori e non solo
CONTRO:
- Non funziona su Windows
- Il test recorder funziona solo per Android ed è stabile solo per Visual Studio
- L’esecuzione dei test è lenta da far schifo
- Il test in cloud costa un occhio della testa anche nella versione Newbie