Автоматизация тестирования приложений для Windows 8

В записи блога, посвященной тестированию приложений для Магазина Windows, мы уделили основное внимание тому, какие аспекты работы приложения необходимо проверить. Можно вручную выполнить проверку областей, обсуждавшихся в предыдущей записи блога, однако более эффективный способ заключается в автоматизации некоторых зон проверки. Автоматизация проверки приложения имеет множество преимуществ. Автоматическое тестирование экономит время и деньги, которые иначе были бы потрачены на тестирование вручную. Созданные автоматические тесты можно многократно запускать при минимальных затратах, и они выполняются значительно быстрее, чем тесты вручную. Это помогает гарантировать стабильно высокое качество вашего приложения и низкий уровень затрат с каждым новым выпуском приложения. Кроме того, автоматическое тестирование повышает тщательность проверки, поскольку даже самый добросовестный тест-инженер может делать ошибки во время утомительного тестирования вручную.

В этой записи блога мы даем рекомендации по автоматизации тестирования приложений для Windows 8 и описываем некоторые методики. Помните о том, что автоматическое тестирование является эффективным методом и требует некоторых начальных инвестиций для получения полной отдачи. Советы и примеры, приведенные в этой записи блога, предназначены для того, чтобы предоставить вам начальные сведения. Но вам потребуется создать на их основе свою собственную инфраструктуру и поддерживать ее. Если вам нужны более простые способы тестирования, ознакомьтесь с недавно опубликованным блогом по тестированию приложений с помощью Visual Studio.

Обычно процесс автоматизации тестирования приложений включает следующие этапы:

  • Установка: автоматизация установки вашего приложения.
  • Активация: автоматизация активации вашего приложения.
  • Выполнение: автоматизация работы вашего приложения, когда оно выполняется.
  • Состояние жизненного цикла: автоматизация состояний приостановки, возобновления и завершения работы вашего приложения.
  • Удаление: автоматизация удаления вашего приложения.

Давайте подробно рассмотрим каждый из этих этапов и соответствующие средства и технологии автоматизации.

Примечание о тестировании в Windows RT

Прежде чем перейти к подробному изучению вопросов автоматизации, мы хотели бы сделать краткое замечание относительно тестирования в Windows RT. Невозможно создавать или портировать процессы x86/64 для выполнения в Windows RT. То есть все средства и технологии, обсуждаемые далее в этой записи блога, не могут применяться для тестирования в Windows RT. Мы рекомендуем использовать Visual Studio для тестирования в Windows RT.

Автоматизация установки вашего приложения

Чтобы протестировать свое приложение, сначала нужно установить его на тестовый компьютер. Для создания пакета приложения и установки его на тестовый компьютер рекомендуется организовать локальный общий доступ к пакету приложения с помощью Visual Studio. В этом случае Visual Studio создает папку, в которой содержатся все необходимые файлы и сценарий PowerShell, устанавливающий соответствующий сертификат и лицензию, вспомогательные пакеты и сам пакет приложения. Вам нужно вручную упаковать свое приложение, но установка осуществляется с использованием PowerShell и может быть автоматизирована. Вот как выполняется установка.

Шаг 1.

Разрешите выполнение сценариев PowerShell. Из соображений безопасности используемая по умолчанию политика выполнения PowerShell запрещает выполнение сценариев PowerShell, поэтому нужно переопределить эту политику. Это действие выполняется вручную, поскольку требует участия пользователя. К счастью, это достаточно сделать один раз для каждого компьютера. Выполните следующую команду в окне PowerShell, чтобы разрешить выполнение сценариев PowerShell.

 PS C:\> Set-ExecutionPolicy AllSigned

 администрирование_Powershell

Рисунок 1. Разрешение выполнения сценариев PowerShell

Шаг 2.

Скопируйте папку пакета приложения, созданную Visual Studio, на тестовый компьютер и выполните сценарий PowerShell Add-AppDevPackage в окне PowerShell. Используйте следующую команду:

 PS C:\JSGrid1_1.0.0.0_AnyCPU_Debug_Test> .\Add-AppDevPackage.ps1

Windows Powershell

Рисунок 2. Запуск сценария Add-AppDevPackage

Шаг 3.

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

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

На первом снимке экрана требуется принять условия лицензии для установки лицензии разработчика. Нажмите кнопку [I Agree] (Принимаю) , если хотите продолжить.

Powershell_лицензия_разработчика

Рисунок 3. Принятие условий лицензии для получения лицензии разработчика

В диалоговом окне [Microsoft account] (Учетная запись Майкрософт) введите свою учетную запись Майкрософт. Если у вас нет учетной записи Майкрософт, щелкните [Sign up] (Регистрация) , чтобы ее создать.

учетная_запись_Майкрософт_вход

Рисунок 4. Вход с использованием учетной записи Майкрософт

Вы получите подтверждение создания вашей лицензии разработчика с указанием даты, когда истекает срок ее действия.

лицензия_разработчика_утверждена

Рисунок 5. Лицензия разработчика успешно получена

На следующем снимке экрана показано, что вы получили лицензию разработчика и ваш пакет успешно установлен.

PS_пакет_успешно_установлен

Рисунок 6. Установка завершена

Автоматизация активации вашего приложения

Теперь ваш пакет приложения установлен на тестовом компьютере, и вы готовы к запуску приложения. Активацию приложения можно автоматизировать с помощью интерфейса IApplicationActivationManager. Этот API доступен в составе Windows SDK, который устанавливается по умолчанию вместе с Visual Studio 2012. Чтобы запустить свое приложение, используйте метод IApplicationActivationManager::ActivateApplication. Следующий фрагмент кода иллюстрирует использование данного метода.

 #include "stdafx.h"
#include <shlobj.h>
#include <stdio.h>
#include <shobjidl.h>
#include <objbase.h>
#include <atlbase.h>
#include <string>

/*++

 Routine Description:

 This routine launches your app using IApplicationActivationManager.

 Arguments:

 strAppUserModelID - AppUserModelID of the app to launch.
 pdwProcessId - Output argument that receives the process id of the launched app.

 Return value:

 HRESULT indicating success/failure

--*/
HRESULT LaunchApp(const std::wstring& strAppUserModelId, PDWORD pdwProcessId)
{
    CComPtr<IApplicationActivationManager> spAppActivationManager;
    HRESULT hrResult = E_INVALIDARG;
    if (!strAppUserModelId.empty())
    {
        // Instantiate IApplicationActivationManager
        hrResult = CoCreateInstance(CLSID_ApplicationActivationManager, NULL, CLSCTX_LOCAL_SERVER, IID_IApplicationActivationManager, (LPVOID*)&spAppActivationManager);

        if (SUCCEEDED(hrResult))
        {
            // This call ensures that the app is launched as the foreground window
            hrResult = CoAllowSetForegroundWindow(spAppActivationManager, NULL);
            
            // Launch the app
            if (SUCCEEDED(hrResult))
            {
                hrResult = spAppActivationManager->ActivateApplication(strAppUserModelId.c_str(), NULL, AO_NONE, pdwProcessId);
            }
        }
    }

    return hrResult;
}

int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hrResult = S_OK;
    if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
    {
        if (argc == 2)
        {
            DWORD dwProcessId = 0;
            ++argv;
            hrResult = LaunchApp(*argv, &dwProcessId);
        }
        else
        {
            hrResult = E_INVALIDARG;
        }

        CoUninitialize();
    }

    return hrResult;
}

 

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

 C:\>Win8AppLaunch.exe Microsoft.BingNews_8wekyb3d8bbwe!AppexNews

В этом фрагменте кода вызов CoAllowSetForegroundWindow играет критически важную роль. Без него приложение запустится, но не будет переведено на передний план. Опыт показывает, что многие разработчики, пытавшиеся написать средство запуска, "наступили на эти грабли".

Наконец, краткое примечание об AppUserModelId. В этом подходе для запуска приложения необходимо ввести AppUserModelId вашего приложения. AppUserModelId служит уникальным идентификатором вашего приложения. Для его получения мы рекомендуем использовать PowerShell. Вот сценарий PowerShell, иллюстрирующий, как можно получить AppUserModelId для всех приложений, установленных на вашем компьютере.

 $installedapps = get-AppxPackage
foreach ($app in $installedapps)
{
    foreach ($id in (Get-AppxPackageManifest $app).package.applications.application.id)
    {
        $app.packagefamilyname + "!" + $id
    }
}

Кроме того, вы можете использовать IAppxManifestReader для перечисления приложений в пакете и получить AppUserModelId с помощью метода IAppxManifestApplication::GetAppUserModelId. Но если вам нужно только одно приложение, которое вы тестируете, значительно проще использовать реестр, чем программировать средство, читающее манифест вашего приложения.

Автоматизация основных функций вашего приложения

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

Модульное тестирование и использование модели автоматизации пользовательского интерфейса дополняют друг друга. Результатом их совместного использования может стать высококачественное приложение, прошедшее всестороннюю проверку. Модульное тестирование позволяет автоматизировать основную бизнес-логику приложения. Тестирование с помощью модели автоматизации пользовательского интерфейса позволяет проверить функции приложения путем имитации использования его интерфейса. Благодаря сочетанию этих подходов вы можете протестировать больше аспектов работы вашего приложения.

Рассмотрим некоторые средства и методики, используемые для реализации каждого из этих подходов.

Модульное тестирование

Модульное тестирование является эффективным способом проверки основных функций вашего приложения. Visual Studio 2012 поддерживает создание модульных тестов для приложений, написанных на C# или C++. Подробную информацию о создании и запуске модульных тестов в Visual Studio 2012 можно прочитать в статье, посвященной созданию и запуску модульных тестов. Если вам уже знакомы другие среды модульного тестирования, вы можете продолжать использовать их для модульного тестирования своего приложения для Магазина Windows.

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

Модульное тестирование полезно для тестирования внутренних механизмов работы вашего приложения, но оно не охватывает пользовательский интерфейс приложения. Для проверки функций приложения через его интерфейс мы рекомендуем использовать модель автоматизации пользовательского интерфейса.

В модели безопасности Windows 8 приложения не имеют прав, необходимых для того, чтобы быть клиентом модели автоматизации пользовательского интерфейса. Но вы можете написать классическое приложение, работающее в качестве клиента модели автоматизации, для которого ваше приложение является целевым. Для этого ваше классическое приложение клиента модели автоматизации должно быть создано с разрешениями UIAccess, как описано в статье Общие сведения о безопасности модели автоматизации пользовательского интерфейса.

Windows SDK содержит средства, являющиеся хорошими примерами клиентов модели автоматизации пользовательского интерфейса: Inspect.exe и AccEvent.exe. Inspect позволяет инспектировать дерево модели автоматизации пользовательского интерфейса обоих видов приложений. AccEvent прослушивает на предмет событий модели автоматизации пользовательского интерфейса. На компьютере с установленным Windows SDK эти средства обычно находятся в папке %ProgramFiles(x86)%\Windows Kits\8.0\bin\<architecture>. Ниже представлены оба эти средства в действии.

inspect.exe

Рисунок 7. Средство Inspect, запущенное для приложения Bing News

средство_accevent

Рисунок 8. Средство AccEvent, запущенное для приложения Bing Sports

Аналогично подходу, используемому этими средствами, вы можете использовать модель автоматизации пользовательского интерфейса для написания классического клиентского приложения, автоматизирующего работу вашего приложения. Изучение способов создания клиента модели автоматизации пользовательского интерфейса можно начать с записи блога, посвященной созданию приложений-клиентов модели автоматизации пользовательского интерфейса на C++ и C#. В этой записи блога рассказывается о традиционной модели автоматизации пользовательского интерфейса, но те же способы могут использоваться и для любого приложения.

Пример клиента модели автоматизации пользовательского интерфейса для контента документа иллюстрирует, как можно использовать шаблоны элементов управления модели автоматизации пользовательского интерфейса для извлечения различных типов контента, таких как заголовки, примечания или выделенный текст, из окна целевого приложения. Пример симуляции сенсорного ввода иллюстрирует использование API-интерфейсов симуляции сенсорного ввода для имитации сенсорного ввода с целью проверки вашего приложения.

Как упоминалось ранее, модульное тестирование и модель автоматизации пользовательского интерфейса являются взаимодополняющими подходами, позволяющими автоматизировать основную бизнес-логику приложения и обращение к его функциям из пользовательского интерфейса. Используйте оба этих подхода для отладки своего приложения.

Автоматизация состояния жизненного цикла вашего приложения

Как было отмечено в записи "Управление жизненным циклом приложений", приложение может переключаться между различными состояниями жизненного цикла. Выполняя тестирование, важно проверить работу своего приложения во всех этих состояниях. Автоматизировать переход в эти состояния можно с помощью средства (PLMDebug), поставляемого вместе со средствами отладки для Windows. Это готовое средство командной строки, которое можно использовать для автоматизации перехода вашего приложения между состояниями жизненного цикла.

Если возможностей PLMDebug недостаточно, вы можете реализовать свое собственное средство изменения состояний жизненного цикла вашего приложения с помощью интерфейса IPackageDebugSettings. Этот API доступен в составе Windows SDK, который устанавливается по умолчанию вместе с Visual Studio. Следующий код иллюстрирует использование API-интерфейса IPackageDebugSettings для изменения состояния жизненного цикла приложения с целью проверки, что оно ожидаемым образом работает во время переходов между состояниями.

 #include "stdafx.h"
#include <stdio.h>
#include <shobjidl.h>
#include <objbase.h>
#include <atlbase.h>
#include <string>

/*++

 Routine Description:

 This routine changes the lifecycle state of a Windows Store app depending on the input argument.

 Arguments:

 strPackageFullName - Package Full Name of the Windows Store app
 strOperation - Operation to take (/enabledebug, /suspend, /resume, /terminate, /cleanTerminate, /disabledebug)

 Return Value:

 HRESULT indicating success/failure

--*/
HRESULT ChangeLifecycleState(const std::wstring& strPackageFullName, const std::wstring& strOperation)
{
    CComPtr<IPackageDebugSettings> spPackageDebugSettings;
    HRESULT hrResult = E_INVALIDARG;

    if (!strPackageFullName.empty() && !strOperation.empty())
    {
        // Instantiate IPackageDebugSettings
        hrResult = CoCreateInstance(CLSID_PackageDebugSettings, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&spPackageDebugSettings));

        // Depending on the operation specified as the command line arg, change the lifecycle state of the app
        if (SUCCEEDED(hrResult))
        {
            if (_wcsicmp(strOperation.c_str(), L"/enableDebug") == 0)
            {
                // Increment debug ref count on the app package - you must do this before you can suspend/resume/terminate
                hrResult = spPackageDebugSettings->EnableDebugging(strPackageFullName.c_str(), NULL, NULL);
            }
            else if (_wcsicmp(strOperation.c_str(), L"/suspend") == 0)
            {
                // Asynchronously suspend the app
                hrResult = spPackageDebugSettings->Suspend(strPackageFullName.c_str());
            }
            else if (_wcsicmp(strOperation.c_str(), L"/resume") == 0)
            {
                // Resume the app
                hrResult = spPackageDebugSettings->Resume(strPackageFullName.c_str());
            }
            else if (_wcsicmp(strOperation.c_str(), L"/terminate") == 0)
            {
                // Terminate the app
                hrResult = spPackageDebugSettings->TerminateAllProcesses(strPackageFullName.c_str());
            }
            else if (_wcsicmp(strOperation.c_str(), L"/cleanTerminate") == 0)
            {
                // Clean terminate the app - suspend, then terminate
                hrResult = spPackageDebugSettings->StartServicing(strPackageFullName.c_str());
                if (SUCCEEDED(hrResult))
                {
                    hrResult = spPackageDebugSettings->StopServicing(strPackageFullName.c_str());
                }
            }
            else if (_wcsicmp(strOperation.c_str(), L"/disableDebug") == 0)
            {
                // Decrement debug ref count on the app package
                hrResult = spPackageDebugSettings->DisableDebugging(strPackageFullName.c_str());
            }
            else
            {
                hrResult = E_INVALIDARG;
            }
        }
    }

    return hrResult;
}

int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hrResult = S_OK;
    if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
    {
        if (argc == 3)
        {
            std::wstring strOperation(argv[1]);
            std::wstring strPackageFullName(argv[2]);
            hrResult = ChangeLifecycleState(strPackageFullName, strOperation);
        }
        else
        {
            hrResult = E_INVALIDARG;
        }

        CoUninitialize();
    }

    return hrResult;
}

 

Если вы скомпилируете этот фрагмент кода как LifecycleManager.exe, вот как его использовать.

 C:\>Win8AppLifecycleManager.exe /enableDebug Microsoft.BingNews_1.2.0.98_x64__8wekyb3d8bbwe

C:\> Win8AppLifecycleManager.exe /suspend Microsoft.BingNews_1.2.0.98_x64__8wekyb3d8bbwe

C:\> Win8AppLifecycleManager.exe /resume Microsoft.BingNews_1.2.0.98_x64__8wekyb3d8bbwe

C:\> Win8AppLifecycleManager.exe /terminate Microsoft.BingNews_1.2.0.98_x64__8wekyb3d8bbwe

C:\> Win8AppLifecycleManager.exe /cleanTerminate Microsoft.BingNews_1.2.0.98_x64__8wekyb3d8bbwe

C:\> Win8AppLifecycleManager.exe /disableDebug Microsoft.BingNews_1.2.0.98_x64__8wekyb3d8bbwe
  

Наконец, краткое примечание о PackageFullName. Во всех рассмотренных нами подходах, предназначенных для управления состояниями жизненного цикла, необходимо использовать PackageFullName в качестве входного аргумента, по которому можно идентифицировать приложение. Чтобы получить PackageFullName, мы рекомендуем использовать командлет PowerShell Get-AppxPackage, как показано в следующем примере (выведенные данные сокращены для удобства чтения).

 PS C:\> Get-AppxPackage

Name              : Microsoft.BingNews
Publisher         : CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
Architecture      : X64
ResourceId        :
Version           : 1.2.0.98
PackageFullName   : Microsoft.BingNews_1.2.0.98_x64__8wekyb3d8bbwe        ←
InstallLocation   : C:\Program Files\WindowsApps\Microsoft.BingNews_1.2.0.98_x64__8wekyb3d8bbwe
IsFramework       : False
PackageFamilyName : Microsoft.BingNews_8wekyb3d8bbwe
PublisherId       : 8wekyb3d8bbwe

Автоматизация удаления вашего приложения

Для удаления приложения мы рекомендуем использовать командлеты PowerShell, в частности Remove-AppxPackage. Вот пример (выведенные данные сокращены для удобства чтения).

 PS C:\> Get-AppxPackage

Name              : Microsoft.SDKSamples.ListViewEssentials.JS
Publisher         : CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
Architecture      : Neutral
ResourceId        :
Version           : 1.0.0.0
PackageFullName   : Microsoft.SDKSamples.ListViewEssentials.JS_1.0.0.0_neutral__8wekyb3d8bbwe            ←
InstallLocation   : C:\Users\user1\Downloads\Samples\Controls_ListViewBasic\JS\bin\Debug\AppX
IsFramework       : False
PackageFamilyName : Microsoft.SDKSamples.ListViewEssentials.JS_8wekyb3d8bbwe
PublisherId       : 8wekyb3d8bbwe

PS C:\> Remove-AppxPackage Microsoft.SDKSamples.ListViewEssentials.JS_1.0.0.0_neutral__8wekyb3d8bbwe

Заключение

В этой записи мы рассмотрели множество рекомендаций, средств и способов автоматизации тестирования приложений. Автоматическое тестирование может быть экономически эффективным способом повышения уровня проверки вашего приложения и обеспечения неизменно высокого качества его работы. Важно помнить, что тестирование вручную также играет ключевую роль при проверке приложения. Оно добавляет в процесс проверки человеческий фактор. Таким образом, сочетание автоматического тестирования и тестирования вручную обеспечит комплексный подход к тестированию вашего приложения.

-- Эшвин Нидамангала (Ashwin Needamangala), ведущий специалист по тестированию, Windows

Благодарю Мита Гоктепе (Mete Goktepe), Дж. Калияна Сундарам (J. Kalyana Sundaram), Бена Бетца (Ben Betz), Уилла Вея (Will Wei), Криса Эдмондса (Chris Edmonds), Крейга Кэмпбелла (Craig Campbell) и Джейка Сабульски (Jake Sabulsky) за помощь при создании этой записи.