Condividi tramite


Xamarin.UITest

Importante

Visual Studio App Center è pianificato per il ritiro il 31 marzo 2025. Anche se è possibile continuare a usare Visual Studio App Center fino a quando non viene completamente ritirato, esistono diverse alternative consigliate a cui è possibile prendere in considerazione la migrazione.

Altre informazioni sulle sequenze temporali di supporto e sulle alternative.

Xamarin.UITest è un framework di test C# che usa NUnit per i test di accettazione dell'interfaccia utente nelle app iOS e Android. Si integra strettamente con i progetti Xamarin.iOS e Xamarin.Android, ma può essere usato anche con progetti iOS e Android nativi. Xamarin.UITest è la libreria di automazione che consente l'esecuzione dei test NUnit nei dispositivi Android e iOS. I test interagiscono con l'interfaccia utente come utente: immissione di testo, tocco di pulsanti e movimenti, ad esempio scorrimenti rapido.

In genere, ogni Xamarin.UITest viene scritto come metodo denominato [Test]. La classe che contiene il test è nota come .[TestFixture] La fixture di test contiene un singolo test o gruppo di test. La fixture è anche responsabile della configurazione per eseguire il test e la pulizia che deve essere eseguita al termine del test. Ogni test deve seguire il modello Arrange-Act-Assert :

  1. Disponi: il test imposterà le condizioni e inizializzerà gli elementi in modo che il test possa essere sottoposto a azione.
  2. Azione: il test interagirà con l'applicazione, immetterà testo, premendo pulsanti e così via.
  3. Assert: il test esamina i risultati delle azioni eseguite nel passaggio Act per determinare la correttezza. Ad esempio, l'applicazione può verificare che venga visualizzato un messaggio di errore specifico.

Il momento migliore per iniziare a usare Xamarin.UITest è durante lo sviluppo di un'applicazione per dispositivi mobili. I test automatizzati vengono scritti come funzionalità in fase di sviluppo in base ai passaggi descritti nell'elenco seguente:

  1. Sviluppare la funzionalità nell'applicazione Android o iOS.
  2. Scrivere i test ed eseguirli in locale per verificare la funzionalità.
  3. Creare una nuova esecuzione di test nel test di App Center o usare un'esecuzione di test esistente.
  4. Compilare l'IPA o l'APK e quindi caricarlo insieme ai test nel test di App Center.
  5. Risolvere eventuali problemi o bug esposti dal test di App Center.
  6. Ripetere il processo passando alla funzionalità successiva per l'applicazione.

Per le applicazioni esistenti che non sono più in fase di sviluppo attivo, potrebbe non essere conveniente aggiungere in modo retroattivo test automatizzati. Al contrario, un approccio migliore consiste nell'usare Xamarin.UITest durante la correzione di bug. Si consideri ad esempio un'applicazione senza test automatizzati e un utente segnala un bug. Uno sviluppatore assegnato per correggere il bug potrebbe eseguire alcune o tutte le azioni seguenti:

  • Verificare manualmente il bug o la regressione.
  • Scrivere un test usando Xamarin.UITest che illustra il bug.
  • Inviare il test ad App Center per ottenere informazioni dettagliate sull'ambito e sull'impatto del bug nei dispositivi pertinenti.
  • Correggere il bug.
  • Verificare che il bug sia stato risolto con un passaggio di Xamarin.UITest.
  • Inviare le correzioni e il test al test di App Center per verificare che il bug sia stato corretto nei dispositivi pertinenti.
  • Controllare il superamento dei test nel controllo della versione.

I test automatizzati dell'interfaccia utente si basano principalmente sull'individuazione e l'interazione con le visualizzazioni sullo schermo. Xamarin.UITest soddisfa questo requisito con due importanti set di API che interagiscono tra loro:

  1. Azioni che possono essere eseguite sulle visualizzazioni: Xamarin.UITest fornisce API che consentono a un test di simulare azioni utente comuni, ad esempio toccando la visualizzazione, immettendo testo o scorrendo rapidamente nella visualizzazione.
  2. Query per individuare le visualizzazioni sullo schermo: parte del framework Xamarin.UITest sono API che individuano le visualizzazioni in una schermata. Le query individuano le viste in fase di esecuzione controllando gli attributi per la visualizzazione e restituendo un oggetto su cui possono funzionare le azioni. L'esecuzione di query in questo modo è una tecnica potente che consente di scrivere i test per le interfacce utente indipendentemente dalle dimensioni dello schermo, dall'orientamento o dal layout

Per semplificare la scrittura di test, Xamarin.UITest fornisce un ciclo REPL (Read-eval-print-loop). REPL consente agli sviluppatori e ai tester di interagire con una schermata mentre l'applicazione è in esecuzione e semplifica la creazione delle query.

Introduzione all'API Xamarin.UITest

Tutte le interazioni di test con l'applicazione per dispositivi mobili si verificano tramite un'istanza di Xamarin.UITest.IApp. Questa interfaccia definisce i metodi fondamentali per il test per collaborare con l'applicazione e interagire con l'interfaccia utente. Esistono due implementazioni concrete di questa interfaccia:

  • Xamarin.UITest.iOS.iOSApp Questa classe automatizza i test su iOS.
  • Xamarin.UITest.Android.AndroidApp Questa classe è destinata all'automazione dei test in Android.

iOSApp gli oggetti e AndroidApp non vengono create direttamente istanze. Vengono invece creati usando la classe helper ConfigureApp . Questa classe è un generatore che garantisce che venga creata correttamente un'istanza di iOSApp o AndroidApp .

È consigliabile usare una nuova IApp istanza per ogni test. Una nuova istanza impedisce lo stato di uno spilling di test in un altro. Esistono due posizioni in cui un test NUnit può inizializzare un'istanza di IApp:

  • SetUp Nel metodo In genere, una fixture di test è un raggruppamento logico di test correlati, ognuno di essi in esecuzione indipendente dall'altro. In questo scenario, l'oggetto IApp deve essere inizializzato nel SetUp metodo, assicurandosi che sia disponibile un nuovo IApp oggetto per ogni test.
  • TestFixtureSetup Nel metodo In alcune situazioni un singolo test può richiedere una propria fixture di test. In questo caso, può essere più opportuno inizializzare l'oggetto IApp una volta nel TestFixtureSetup metodo .

Dopo IApp la configurazione, un test può iniziare a interagire con l'applicazione sottoposta a test. A tale scopo, è necessario ottenere riferimenti alle visualizzazioni visibili sullo schermo. Molti metodi in Xamarin.UITest accettano un Func<AppQuery, AppQuery> parametro per individuare le visualizzazioni. Ad esempio, il frammento di codice seguente mostra come toccare un pulsante:

app.Tap(c=>c.Button("ValidateButton"));

Esistono due implementazioni dell'interfaccia IApp all'interno del framework Xamarin.UITest, una per iOS e una per Android.

Inizializzare IApp per le applicazioni iOS

Quando Xamarin.UITest esegue un test in iOS, avvia un'istanza del simulatore iOS, distribuisce l'applicazione, la avvia e inizia a eseguire i test. L'applicazione iOS deve essere già compilata. Xamarin.UITest non compilerà l'applicazione e creerà automaticamente il bundle di app.

Il AppBundle metodo può essere usato per specificare dove trovare il bundle dell'app nel file system. Esistono due modi per eseguire questa operazione, con un percorso assoluto o un percorso relativo. Questo frammento di codice mostra l'uso di un percorso assoluto per il bundle dell'app:

IApp app = ConfigureApp
    .iOS
    .AppBundle("/path/to/iosapp.app")
    .StartApp();

I percorsi parziali devono essere relativi all'assembly Xamarin.UITest. Questo frammento di codice è un esempio:

IApp app = ConfigureApp
    .iOS
    .AppBundle("../../../iOSAppProject/bin/iPhoneSimulator/Debug/iosapp.app")
    .StartApp();

L'esempio di percorso relativo indica AppBundle di passare verso l'alto tre directory dall'assembly Xamarin.UITest e quindi spostarsi verso il basso nell'albero del progetto di applicazione iOS per trovare il bundle dell'app.

ConfigureApp dispone di altri metodi per la configurazione di IApp. Per altri dettagli, vedere la classe iOSAppConfigurator . Alcuni dei metodi più interessanti sono descritti nella tabella seguente:

Metodo Descrizione
AppBundle Questo metodo specifica il percorso del bundle dell'app da usare durante il test.
Debug Questo metodo consentirà di eseguire il debug dei messaggi di registrazione nel test runner. Questo metodo è utile per risolvere i problemi relativi all'esecuzione dell'applicazione nel simulatore.
DeviceIdentifier Configura il dispositivo da usare con l'identificatore del dispositivo. Questo metodo verrà descritto in modo più dettagliato di seguito.
EnableLocalScreenshots Abilitare gli screenshot durante l'esecuzione dei test in locale. Gli screenshot sono sempre abilitati quando i test vengono eseguiti nel cloud.

Per altre informazioni su come eseguire test iOS in un simulatore iOS specifico, vedere Determinare l'ID dispositivo per un simulatore iOS.

Inizializzare applicazioni IApp per Android

Xamarin.UITest distribuirà un APK esistente in un dispositivo collegato o in un'istanza dell'emulatore Android già in esecuzione. L'app verrà avviata e quindi verrà eseguito il test. Xamarin.UITest non può compilare l'APK né avviare un'istanza dell'emulatore Android.

Il ApkFile metodo di IApp viene usato per specificare dove si trova il file system dell'APK. Esistono due modi per eseguire questa operazione, con un percorso assoluto o un percorso relativo. Questo frammento di codice mostra l'uso di un percorso assoluto per l'APK:

IApp app = ConfigureApp
    .Android
    .ApkFile("/path/to/android.apk")
    .StartApp();

I percorsi parziali devono essere relativi all'assembly Xamarin.UITest. Questo frammento di codice è un esempio:

IApp app = ConfigureApp
    .Android
    .ApkFile("../../../AndroidProject/bin/Debug/android.apk")
    .StartApp();

L'esempio di percorso relativo indica ApkFile di salire tre directory dall'assembly Xamarin.UITest e quindi passare verso il basso l'albero del progetto di applicazione Android per trovare il file apk.

Se sono connessi più dispositivi o emulatori, Xamarin.UITest arresterà l'esecuzione dei test e visualizzerà un messaggio di errore perché non è in grado di risolvere la destinazione prevista per il test. In questo caso, è necessario specificare l'ID seriale del dispositivo o dell'emulatore per eseguire il test. Si consideri, ad esempio, l'output seguente dal adb devices comando che elenca tutti i dispositivi (o gli emulatori) collegati al computer (insieme al relativo ID seriale):

$ adb devices
List of devices attached
192.168.56.101:5555 device
03f80ddae07844d3    device

Il dispositivo può essere specificato usando il DeviceSerial metodo:

IApp app = ConfigureApp.Android.ApkFile("/path/to/android.apk")
                               .DeviceSerial("03f80ddae07844d3")
                               .StartApp();

Interazione con l'interfaccia utente

Per interagire con le visualizzazioni, molti IApp metodi accettano un Func<AppQuery, AppQuery> delegato per individuare la visualizzazione. Questo delegato usa AppQuery questo oggetto all'interno del modo in cui Xamarin.UITest individua le visualizzazioni.

AppQuery è un'interfaccia fluente per la creazione delle query per individuare le visualizzazioni. Dei metodi forniti AppQuery , il Marked metodo è uno dei più semplici e più flessibili. Questo metodo usa un'euristica per provare a individuare le visualizzazioni e verrà illustrato in modo più dettagliato nella sezione seguente. Per il momento, è importante comprendere che IApp ha molti metodi per interagire con un'applicazione. Questi metodi usano un Func<AppQuery, AppQuery> oggetto per ottenere un riferimento alla visualizzazione con cui interagire. Di seguito sono elencati alcuni dei metodi più interessanti forniti da AppQuery :

Metodo Descrizione
Button Individua uno o più pulsanti sullo schermo.
Class Tenterà di individuare le visualizzazioni di una classe specificata.
Id Tenterà di individuare una vista con l'ID specificato.
Index . Restituirà una vista da una raccolta di visualizzazioni corrispondenti. In genere usato insieme ad altri metodi. Accetta un indice in base zero.
Marked Restituirà una vista in base all'euristica descritta di seguito.
Text Corrisponderà alle visualizzazioni che contengono il testo specificato.
TextField Corrisponderà a un oggetto Android EditText o iOS UITextField.

Ad esempio, il metodo seguente illustra come simulare un tocco su un pulsante denominato "SaveUserdataButton":

app.Tap(c=>c.Marked("SaveUserDataButton"));

Poiché AppQuery è un'interfaccia fluente, è possibile concatenare più chiamate al metodo insieme. Si consideri questo esempio più complicato di toccare una visualizzazione:

app.Tap(c=>c.Marked("Pending")
            .Parent()
            .Class("AppointmentListCell").Index(0));

In questo caso, verrà AppQuery prima trovato una visualizzazione contrassegnata Pending, quindi selezionare il primo padre di tale visualizzazione che è un AppointmentListCell tipo.

Può essere difficile provare a creare queste query esaminando un'app per dispositivi mobili. Xamarin.UITest fornisce un REPL che può essere usato per esplorare la gerarchia di visualizzazione di uno schermo, sperimentare la creazione di query e usarli per interagire con un'applicazione.

Uso di REPL

L'unico modo per avviare REPL consiste nell'richiamare il IApp.Repl metodo all'interno di un test esistente. Ciò richiede la creazione di un oggetto NUnit TestFixture, la configurazione di un'istanza di IApp che può essere usata in un Test metodo. Il frammento di codice seguente illustra un esempio di come eseguire questa operazione:

[TestFixture]
public class ValidateCreditCard
{
    IApp app;

    [SetUp]
    public void Setup()
    {
        app = ConfigureApp.Android.ApkFile("/path/to/application.apk").StartApp();
    }
    [Test]
    public void CreditCardNumber_TooLong_DisplayErrorMessage()
    {
        app.Repl();
    }
}

Per eseguire il test facendo clic con il pulsante destro del mouse sulla barra di Visual Studio e selezionando Esegui:

Screenshot del menu popup con le opzioni di esecuzione per un test

Il test verrà eseguito e, quando viene richiamato il Repl metodo, Xamarin.UITest avvierà il REPL in una sessione del terminale, come illustrato nello screenshot seguente:

Screenshot del terminale macOS che esegue il REPL Xamarin.UITest

RePL ha inizializzato un'istanza di IAppappdenominata , che interagisce con l'applicazione. Una delle prime operazioni da eseguire consiste nell'esplorare l'interfaccia utente. RePL ha un tree comando per eseguire questa operazione. Verrà stampata la gerarchia delle visualizzazioni nella schermata visualizzata. Ad esempio, prendere in considerazione lo screenshot seguente di un'applicazione:

Screenshot di un'applicazione di esempio in esecuzione in un iPhone

È possibile usare il tree comando per visualizzare la gerarchia seguente di questa schermata:

App has been initialized to the 'app' variable.
Exit REPL with ctrl-c or see help for more commands.

>>> tree
[UIWindow > UILayoutContainerView]
  [UINavigationTransitionView > ... > UIView]
    [UITextView] id: "CreditCardTextField"
      [_UITextContainerView]
    [UIButton] id: "ValidateButton"
      [UIButtonLabel] text: "Validate Credit Card"
    [UILabel] id: "ErrorrMessagesTestField"
  [UINavigationBar] id: "Credit Card Validation"
    [_UINavigationBarBackground]
      [_UIBackdropView > _UIBackdropEffectView]
      [UIImageView]
    [UINavigationItemView]
      [UILabel] text: "Credit Card Validation"
>>>

È possibile notare che in questa visualizzazione è presente un UIButton oggetto con ValidateButtonid. È possibile usare le informazioni visualizzate dal tree comando per creare le query necessarie per individuare e interagire con le visualizzazioni. Ad esempio, il codice seguente simula un tocco sul pulsante:

app.Tap(c=>c.Marked("ValidateButton"))

Poiché i comandi vengono immessi, vengono ricordati dal REPL in un buffer. RePL fornisce un copy comando che copia il contenuto di questo buffer negli Appunti. Ciò consente di prototipiare un test. È possibile copiare il lavoro eseguito negli Appunti con copye quindi incollare tali comandi all'interno di un [Test]oggetto .

Uso di contrassegnato per individuare le visualizzazioni

Il metodo AppQuery.Marked è un modo pratico e potente per eseguire query per le visualizzazioni sullo schermo. Funziona controllando la gerarchia di visualizzazione per una visualizzazione sullo schermo, cercando di corrispondere alle proprietà nella visualizzazione con alla stringa specificata. Marked funziona in modo diverso a seconda del sistema operativo.

Ricerca di visualizzazioni iOS con contrassegnata

Le visualizzazioni iOS si trovano usando uno degli attributi seguenti:

  • dell'oggetto AccessibilityIdentifier della visualizzazione
  • dell'oggetto AccessibilityLabel della visualizzazione

Si consideri, ad esempio, il frammento di codice C# seguente che crea un UILabel oggetto e imposta :AccessibilityLabel

UILabel errorMessagesTextField = new UILabel(new RectangleF(10, 210, 300, 40));
errorMessagesTextField.AccessibilityLabel = "ErrorMessagesTextField";
errorMessagesTextField.Text = String.Empty;

Questa vista può essere posizionata dalla query seguente:

AppResult[] results = app.Marked("ErrorMessagesTextField");

Ricerca di visualizzazioni Android con contrassegnato

Le visualizzazioni Android si trovano in base a una delle proprietà seguenti:

  • dell'oggetto Id della visualizzazione
  • dell'oggetto ContentDescription della visualizzazione
  • oggetto Text di una visualizzazione

Si consideri ad esempio un layout Android con il pulsante seguente definito:

<Button
    android:text="Action 1"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:id="@+id/action1_button"
    android:layout_weight="1"
    android:layout_marginLeft="5dp" />

È possibile notare che il android:id pulsante è action1_button e che è android:textAzione 1. Una delle due query seguenti individua il pulsante sullo schermo:

  • app.Query(c=>c.Marked("action1_button"));
  • app.Query(c=>c.Marked("Action 1"));

Controllo dell'applicazione con Xamarin.UITest.IApp

Dopo IApp aver configurato e inizializzato, il test può iniziare a interagire con l'applicazione. Un esempio di metodo che usa Func<AppQuery, AppQuery> è il IApp.Query() metodo . Questo metodo eseguirà la query e restituirà i risultati. L'esempio più semplice è illustrato nel frammento di codice seguente, che restituisce un elenco di tutte le visualizzazioni visibili sullo schermo:

AppResult[] results = app.Query(c=>c.All())

La tabella seguente illustra alcuni altri esempi di uso AppQuery per individuare le visualizzazioni sullo schermo:

Sintassi Risultati
app.Query(c=>c.Class("UILabel")) Il .Class() metodo eseguirà una query per le viste che sono una sottoclasse di un iOS UILabel.
app.Query(c=>c.Id("txtUserName")) Il .Id() metodo eseguirà una query per le visualizzazioni con un IdtxtUserName.
app.Query(c=>c.Class("UILabel").Text("Hello, World")) Individua tutte le UILabel classi con il testo "Hello, World".
results = app.Query(c=>c.Marked("ValidateButton")) Restituisce tutte le visualizzazioni contrassegnate con il testo specificato. Il Marked metodo è un metodo utile che può semplificare le query. Verrà illustrata nella sezione seguente.

La tabella successiva elenca alcuni (ma non tutti) dei metodi forniti da IApp che possono essere usati per interagire con o modificare visualizzazioni sullo schermo:

Esempio Descrizione
PressEnter Premere il tasto INVIO nell'app.
Tap Simula un movimento tocco/tocco sull'elemento corrispondente.
EnterText Immette il testo nella visualizzazione. In un'applicazione iOS, Xamarin.UITest immetterà il testo usando la tastiera temporanea. Al contrario, Xamarin.UITest non userà la tastiera Android, immetterà direttamente il testo nella visualizzazione.
WaitForElement Sospende l'esecuzione del test fino a quando le visualizzazioni non vengono visualizzate sullo schermo.
Screenshot(String) Acquisisce uno screenshot dell'applicazione nello stato corrente e lo salva su disco. Restituisce un FileInfo oggetto con informazioni sullo screenshot acquisito.
Flash Questo metodo causerà la visualizzazione selezionata "flash" o "flicker" sullo schermo.

Per altre informazioni sull'interfaccia, vedere la documentazione dell'APIIApp per IApp, AndroidAppe iOSApp.

Come esempio di come usare questi metodi, considerare il test seguente per lo screenshot visualizzato sopra. Questo test immetterà un numero di 17 cifre per una carta di credito in un campo di testo e quindi toccare un pulsante sullo schermo. Verrà quindi esaminata la schermata per un messaggio di errore che informa l'utente che il numero è troppo lungo per essere un numero di carta di credito valido:

[Test]
public void CreditCardNumber_TooLong_DisplayErrorMessage()
{
    /* Arrange - set up our queries for the views */
    // Nothing to do here, app has been instantiated in the [SetUp] method.

    /* Act */
    app.EnterText(c => c.Marked("CreditCardTextField"), new string('9', 17));
    // Screenshot can be used to break this test up into "steps".
    // The screenshot can be inspected after the test run to verify
    // the visual correctness of the screen.
    app.Screenshot("Entering a 17 digit credit card number.");

    app.Tap(c => c.Marked("ValidateButton"));
    app.Screenshot("The validation results.");

    /* Assert */
    AppResult[] result = app.Query(c => c.Class("UILabel").Text("Credit card number is too long."));
    Assert.IsTrue(result.Any(), "The error message isn't being displayed.");
}

Questo test usa anche il Screenshot metodo per scattare foto in punti chiave durante l'esecuzione del test. Quando questo test viene eseguito, App Center prenderà gli screenshot e li visualizzerà nei risultati del test. Il metodo consente di suddividere un test in passaggi e fornire descrizioni per gli screenshot.