Xamarin.UITest

Важно!

Прекращение поддержки Центра приложений Visual Studio запланировано на 31 марта 2025 г. Хотя вы можете продолжать использовать Центр приложений Visual Studio, пока он не будет полностью выведен из эксплуатации, существует несколько рекомендуемых вариантов, на которые вы можете рассмотреть возможность миграции.

Узнайте больше о сроках поддержки и альтернативных вариантах.

Xamarin.UITest — это платформа тестирования C#, использующий NUnit для приемочных тестов пользовательского интерфейса в приложениях iOS и Android. Он тесно интегрируется с проектами Xamarin.iOS и Xamarin.Android, но также может использоваться с собственными проектами iOS и Android. Xamarin.UITest — это библиотека автоматизации , которая позволяет выполнять тесты NUnit на устройствах Android и iOS. Тесты взаимодействуют с пользовательским интерфейсом так же, как пользователь: ввод текста, нажатие кнопок и жесты, такие как прокрутки.

Как правило, каждый Xamarin.UITest записывается как метод , который называется [Test]. Класс, содержащий тест, называется [TestFixture]. Тестовый прибор содержит один тест или группу тестов. Средство также отвечает за настройку, чтобы выполнить тестовый запуск и очистку, которая должна быть выполнена после завершения теста. Каждый тест должен соответствовать шаблону Arrange-Act-Assert :

  1. Упорядочить. Тест настроит условия и инициализирует элементы, чтобы можно было выполнить тест.
  2. Действие. Тест будет взаимодействовать с приложением, вводить текст, нажимать кнопки и т. д.
  3. Assert. Тест проверяет результаты действий, выполняемых на шаге Act, чтобы определить правильность. Например, приложение может проверить, отображается ли определенное сообщение об ошибке.

Лучшее время для начала работы с Xamarin.UITest — это разработка мобильного приложения. Автоматические тесты написаны как компонент, который разрабатывается в соответствии с инструкциями, описанными в следующем списке:

  1. Разработка функции в приложении Android или iOS.
  2. Напишите тесты и запустите их локально для проверки функциональности.
  3. Создайте тестовый запуск в центре приложений Test или используйте существующий тестовый запуск.
  4. Скомпилируйте IPA или APK-файл, а затем отправьте его вместе с тестами в Центр приложений Test.
  5. Исправьте все проблемы или ошибки, предоставляемые тестом Центра приложений.
  6. Повторите процесс, перейдя к следующей функции приложения.

Для существующих приложений, которые больше не находятся в активной разработке, добавление автоматических тестов может оказаться экономически эффективным. Вместо этого лучше использовать Xamarin.UITest при исправлении ошибок. Например, рассмотрим приложение, которое не имеет автоматического тестирования и пользователь сообщает об ошибке. Разработчик, которому назначено исправление этой ошибки, может выполнить некоторые (или все) из следующих действий:

  • Проверьте ошибку или регрессию вручную.
  • Напишите тест с помощью Xamarin.UITest, демонстрирующий ошибку.
  • Отправьте тест в центр приложений, чтобы получить представление о область и влиянии ошибки на соответствующие устройства.
  • Исправление ошибки.
  • Убедитесь, что ошибка исправлена, передав Xamarin.UITest.
  • Отправьте исправления и протестируйте в Центр приложений Test, чтобы убедиться, что ошибка была исправлена на соответствующих устройствах.
  • Проверьте прохождение тестов в управлении версиями.

Автоматическое тестирование пользовательского интерфейса в значительной степени зависит от поиска представлений на экране и взаимодействия с ними. Xamarin.UITest удовлетворяет этому требованию два важных набора API, которые работают друг с другом:

  1. Действия , которые можно выполнять с представлениями. Xamarin.UITest предоставляет API-интерфейсы, позволяющие тесту имитировать обычные действия пользователей, такие как касание представления, ввод текста или прокрутка представления.
  2. Запросы для поиска представлений на экране. Часть платформы Xamarin.UITest — это API- интерфейсы, которые будут находить представления на экране. Запросы находят представления во время выполнения, проверяя атрибуты представления и возвращая объект, с которым могут работать действия. Запросы таким образом — это мощный метод, позволяющий создавать тесты для пользовательских интерфейсов независимо от размера экрана, ориентации или макета.

Чтобы упростить написание тестов, Xamarin.UITest предоставляет цикл read-eval-print- (REPL). REPL позволяет разработчикам и тестировщикам взаимодействовать с экраном во время работы приложения и упрощает создание запросов.

Общие сведения об API Xamarin.UITest

Все тестовые взаимодействия с мобильным приложением происходят через экземпляр Xamarin.UITest.IApp. Этот интерфейс определяет методы, необходимые для совместной работы теста с приложением и взаимодействия с пользовательским интерфейсом. Существует две конкретные реализации этого интерфейса:

  • Xamarin.UITest.iOS.iOSApp Этот класс автоматизирует тесты для iOS.
  • Xamarin.UITest.Android.AndroidApp Этот класс предназначен для автоматизации тестов на Android.

iOSApp Объекты и AndroidApp не создаются напрямую. Вместо этого они создаются с помощью вспомогательного ConfigureApp класса. Этот класс является построителем, гарантирующим правильность создания экземпляра iOSApp или AndroidApp .

Рекомендуется использовать новый IApp экземпляр для каждого теста. Новый экземпляр предотвращает переключение состояния одного теста на другой. Существует два места, где тест NUnit может инициализировать экземпляр .IApp

  • В методе SetUp Обычно средство тестирования представляет собой логическую группу связанных тестов, каждый из которых выполняется независимо от другого. В этом сценарии необходимо инициализировать IApp в методе SetUp , гарантируя, что новый IApp объект доступен для каждого теста.
  • В методе TestFixtureSetup В некоторых ситуациях для одного теста может потребоваться собственный тестовый прибор. В этом случае имеет смысл инициализировать IApp объект один раз в методе TestFixtureSetup .

После IApp настройки тест может начать взаимодействовать с тестируемым приложением. Для этого необходимо получить ссылки на представления, которые отображаются на экране. Многие методы в Xamarin.UITest принимают Func<AppQuery, AppQuery> параметр для поиска представлений. Например, в следующем фрагменте кода показано, как нажать кнопку:

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

Существует две реализации IApp интерфейса в платформе Xamarin.UITest: одна для iOS и другая для Android.

Инициализация IApp для приложений iOS

Когда Xamarin.UITest запускает тест в iOS, он запускает экземпляр симулятора iOS, развертывает приложение, запускает его и начинает выполнение тестов. Приложение iOS уже должно быть создано. Xamarin.UITest не компилирует приложение и не создает пакет приложений.

Метод AppBundle можно использовать, чтобы указать, где в файловой системе можно найти пакет приложений. Это можно сделать двумя способами: абсолютным или относительным путем. В этом фрагменте кода показано использование абсолютного пути к пакету приложений:

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

Частичные пути должны быть относительно сборки Xamarin.UITest. Этот фрагмент кода является примером:

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

В примере относительного пути показано AppBundle , как перейти вверх по трем каталогам из сборки Xamarin.UITest, а затем перейти вниз по дереву проекта приложения iOS, чтобы найти пакет приложений.

ConfigureApp имеет другие методы, помогающие настроить IApp. Дополнительные сведения см. в разделе Класс iOSAppConfigurator . Некоторые из более интересных методов описаны в следующей таблице:

Метод Описание
AppBundle Этот метод задает путь к пакету приложений, который будет использоваться при тестировании.
Debug Этот метод включает ведение журнала сообщений отладки в средстве выполнения тестов. Этот метод полезен для устранения проблем с запуском приложения в симуляторе.
DeviceIdentifier Настраивает устройство для использования с идентификатором устройства. Этот метод будет подробно описан ниже.
EnableLocalScreenshots Включение снимков экрана при локальном выполнении тестов. Снимки экрана всегда включены при выполнении тестов в облаке.

Дополнительные сведения о том, как выполнять тесты iOS в определенном симуляторе iOS, см. в статье Определение идентификатора устройства для симулятора iOS.

Инициализация приложений IApp для Android

Xamarin.UITest развернет существующий пакет APK на подключенном устройстве или экземпляре эмулятора Android, который уже запущен. Будет запущено приложение, а затем будет запущен тест. Xamarin.UITest не может выполнить сборку APK и запустить экземпляр эмулятора Android.

Метод ApkFileIApp используется, чтобы указать, где в файловой системе можно найти APK. Это можно сделать двумя способами: абсолютным или относительным путем. В этом фрагменте кода показано использование абсолютного пути к APK:

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

Частичные пути должны быть относительно сборки Xamarin.UITest. Пример этого фрагмента кода:

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

В примере относительного пути показано ApkFile , как перейти вверх по трем каталогам из сборки Xamarin.UITest, а затем перейти вниз по дереву проекта приложения Android, чтобы найти apk-файл.

Если подключено несколько устройств или эмуляторов, Xamarin.UITest остановит выполнение теста и отобразит сообщение об ошибке, так как не удается решить, какой целевой объект предназначен для теста. В этом случае необходимо указать серийный идентификатор устройства или эмулятора для запуска теста. Например, рассмотрим следующие выходные данные adb devices команды, в которой перечислены все устройства (или эмуляторы), подключенные к компьютеру (вместе с их серийным идентификатором):

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

Устройство можно указать с помощью DeviceSerial метода :

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

Взаимодействие с пользовательским интерфейсом

Для взаимодействия с представлениями многие IApp методы принимают Func<AppQuery, AppQuery> делегат для поиска представления. Этот делегат использует AppQuery это в основе того, как Xamarin.UITest находит представления.

AppQuery — это текучий интерфейс для создания запросов для поиска представлений. Из методов, которые AppQuery предоставляют, Marked метод является одним из самых простых и гибких. Этот метод использует эвристические методы для поиска представлений и будет более подробно рассмотрен в следующем разделе. Сейчас важно понимать, что IApp имеет множество методов взаимодействия с приложением. Эти методы используют для Func<AppQuery, AppQuery> получения ссылки на представление для взаимодействия. Ниже перечислены некоторые из более интересных методов AppQuery .

Метод Описание
Button Найдите одну или несколько кнопок на экране.
Class Попытается найти представления, которые относятся к указанному классу.
Id Попытается найти представление с указанным идентификатором.
Index . Возвращает одно представление из коллекции соответствующих представлений. Обычно используется в сочетании с другими методами. Принимает отсчитываемый от нуля индекс.
Marked Возвращает представление в соответствии с эвристики, описанной ниже.
Text Будет соответствовать представлениям, содержащим предоставленный текст.
TextField Соответствует android EditText или iOS UITextField.

Например, следующий метод показывает, как имитировать касание кнопки с именем SaveUserdataButton:

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

Так как AppQuery является текучим интерфейсом, можно связать несколько вызовов методов. Рассмотрим этот более сложный пример касания представления:

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

AppQuery Здесь сначала найдет представление с пометкой Pending, а затем выберет первый родительский элемент этого представления, который является типомAppointmentListCell.

Это может быть сложно создать эти запросы, просмотрев мобильное приложение. Xamarin.UITest предоставляет REPL, который можно использовать для просмотра иерархии представлений экрана, экспериментирования с созданием запросов и их использования для взаимодействия с приложением.

Использование REPL

Единственный способ запустить REPL — вызвать IApp.Repl метод в существующем тесте. Для этого необходимо создать NUnit TestFixture, настроив экземпляр IApp , который можно использовать в методе Test . В следующем фрагменте кода показан пример того, как это сделать:

[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();
    }
}

Чтобы запустить тест, щелкните правой кнопкой мыши в области Visual Studio и выберите Выполнить:

Снимок экрана: всплывающее меню с параметрами запуска для теста

Тест будет запущен, и при вызове Repl метода Xamarin.UITest запустит REPL в сеансе терминала, как показано на следующем снимке экрана:

Снимок экрана: терминал macOS с Xamarin.UITest REPL

REPL инициализировал IApp экземпляр с именем app, который взаимодействует с приложением. Одним из первых действий является изучение пользовательского интерфейса. RePL имеет tree команду для этого. Он выведет иерархию представлений на отображаемом экране. В качестве примера рассмотрим следующий снимок экрана приложения:

Снимок экрана: пример приложения, работающего на iPhone

С помощью tree команды можно отобразить следующую иерархию этого экрана:

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"
>>>

Мы видим, что в этом представлении есть элемент с элементом UIButtonidValidateButton. Мы можем использовать сведения, отображаемые командой , tree для создания необходимых запросов для поиска представлений и взаимодействия с ними. Например, следующий код имитирует касание кнопки:

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

По мере ввода команд они запоминаются REPL в буфере. REPL предоставляет copy команду, которая копирует содержимое этого буфера в буфер обмена. Это позволяет нам создать прототип теста. Мы можем скопировать работу, выполненную в REPL, в буфер обмена с copyпомощью , а затем вставить эти команды в [Test].

Использование помеченных для поиска представлений

Метод AppQuery.Marked — это удобный и эффективный способ запроса представлений на экране. Он работает путем проверки иерархии представлений для представления на экране, пытаясь сопоставить свойства представления с предоставленной строкой. Marked работает по-разному в зависимости от операционной системы.

Поиск представлений iOS с пометкой

Представления iOS будут находиться с помощью одного из следующих атрибутов:

  • элемента AccessibilityIdentifier представления
  • элемента AccessibilityLabel представления

В качестве примера рассмотрим следующий фрагмент кода C#, который создает UILabel и задает AccessibilityLabel:

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

Это представление можно найти с помощью следующего запроса:

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

Поиск представлений Android с пометкой

Представления Android будут находиться на основе одного из следующих свойств:

  • элемента Id представления
  • элемента ContentDescription представления
  • объекта Text представления

Например, рассмотрим макет Android, для которого определена следующая кнопка:

<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" />

Мы видим, что android:id элемент этой кнопки является action1_button , android:text а — действием 1. Один из следующих двух запросов будет находить кнопку на экране:

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

Управление приложением с помощью Xamarin.UITest.IApp

После IApp настройки и инициализации тест может начать взаимодействие с приложением. Одним из примеров метода, использующий Func<AppQuery, AppQuery> метод , IApp.Query() является метод . Этот метод выполнит запрос и вернет результаты. Самый простой пример показан в следующем фрагменте, который возвращает список всех представлений, видимых на экране:

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

В следующей таблице показаны некоторые другие примеры использования AppQuery для поиска представлений на экране.

Синтаксис Результаты
app.Query(c=>c.Class("UILabel")) Метод .Class() будет запрашивать представления, которые являются подклассом iOS UILabel.
app.Query(c=>c.Id("txtUserName")) Метод .Id() запрашивает представления с IdtxtUserName.
app.Query(c=>c.Class("UILabel").Text("Hello, World")) Находит все UILabel классы с текстом "Hello, World".
results = app.Query(c=>c.Marked("ValidateButton")) Возвращает все представления, помеченные указанным текстом. Метод Marked является полезным методом, который может упростить запросы. Он будет рассматриваться в следующем разделе.

В следующей таблице перечислены некоторые (но не все) методы, предоставляемые , IApp которые можно использовать для взаимодействия с представлениями на экране или управления ими:

Пример Описание
PressEnter Нажмите клавишу ВВОД в приложении.
Tap Имитирует жест касания или касания для соответствующего элемента.
EnterText Вводит текст в представление. В приложении iOS Xamarin.UITest вводит текст с помощью мягкой клавиатуры. В отличие от этого, Xamarin.UITest не будет использовать клавиатуру Android, а будет напрямую вводить текст в представление.
WaitForElement Приостанавливает выполнение теста до тех пор, пока на экране не появятся представления.
Screenshot(String) Создает снимок экрана приложения в текущем состоянии и сохраняет его на диск. Он возвращает FileInfo объект со сведениями о снимку экрана.
Flash Этот метод приведет к тому, что выбранное представление будет мигать или мигать на экране.

Дополнительные сведения об интерфейсе см. в IAppдокументации по API для IApp, AndroidAppи iOSApp.

В качестве примера использования этих методов рассмотрим следующий тест для снимка экрана, показанного выше. Этот тест введет 17-значный номер для кредита, карта в текстовое поле, а затем нажмите кнопку на экране. Затем он проверит экран на наличие сообщения об ошибке, информирующего пользователя о том, что номер слишком длинный, чтобы быть допустимым номером карта кредита:

[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.");
}

Этот тест также использует Screenshot метод для создания снимков в ключевых точках во время выполнения теста. При запуске этого теста Центр приложений сделает снимки экрана и отобразит их в результатах теста. Метод позволяет разбить тест на шаги и предоставить описания для снимков экрана.