Windows 8 앱 테스트 자동화

Windows 8 앱 개발자 블로그

Windows 8 엔지니어링 팀에서 제공하는 Windows 8용 Metro 스타일 앱 개발의 이해

Windows 8 앱 테스트 자동화

  • Comments 1

이전에 Windows 스토어 앱을 테스트하는 방법에 대한 글을 통해 앱을 테스트할 때 필요한 사항에 대해 알아보았습니다. 이 글에서 설명한 대로 검증 영역은 수동으로 실행할 수 있지만 그중 일부를 자동화하면 테스트 효율성을 더욱 높일 수 있습니다. 앱 검증을 자동화하면 수동 테스트에 비해 시간과 비용이 절감되므로 사용자에게도 많은 이점이 있습니다. 특히 자동화 테스트는 한 번만 생성해도 최소 비용으로 여러 차례 반복해서 실행할 수 있을 뿐 아니라 수동 테스트에 비해 속도도 훨씬 빠릅니다. 따라서 앱의 품질을 높일 수 있고 매번 새로운 앱을 출시할 때마다 들어가는 비용도 절감할 수 있습니다. 자동화 테스트를 사용하면 검증 정확도도 향상됩니다. 아무리 성실한 테스터라고 해도 지루한 수동 테스트 과정에서 실수를 할 수 있기 때문입니다.

이번 글에서는 Windows 8 앱 테스트 자동화와 관련한 몇 가지 팁과 기술을 소개하겠습니다. 자동화 테스트는 워낙 영향력이 큰 기술인 만큼 제대로 활용할 수 있기까지는 많은 노력이 필요합니다. 이 글에서 제시하는 방법이나 예제는 첫 발을 내딛기 위한 준비 단계라 할 수 있으며, 이를 바탕으로 자신만의 노하우를 구축하고 더욱 발전시켜 나가시기 바랍니다. 이보다 가볍게 접근할 수 있는 기술이 필요할 경우에는 Visual Studio 기반의 앱 테스트에 대한 최근 블로그 글을 참고하세요.

일반적인 앱 테스트 자동화 절차는 다음과 같습니다.

  • 설치: 앱 설치를 자동화합니다.
  • 활성화: 앱 활성화를 자동화합니다.
  • 런타임: 실행 중인 앱을 자동화합니다.
  • 수명 주기 상태: 일시 중지, 재개, 종료된 앱을 자동화합니다.
  • 제거: 앱 제거를 자동화합니다.

그럼, 각 단계에 대해 자세히 알아보고 단계별로 사용되는 자동화 도구/기술에 대해 살펴보겠습니다.

Windows RT 기반 테스트의 참고사항

본격적으로 자동화 관련 주제에 들어가기에 앞서 Windows RT 기반의 테스트에 대해 간단히 살펴보겠습니다. 이 테스트에서는 x86/64 프로세스를 Windows RT에서 실행하도록 빌드하거나 포팅할 수 없습니다. 따라서 이 글에서 소개하는 도구와 기술을 Windows RT 기반 테스트에 모두 적용해서는 안 됩니다. 그 대신에 Windows RT 기반 테스트를 위한 Visual Studio를 사용할 것을 권장합니다.

앱 설치 자동화

앱을 테스트하려면 우선 테스트 시스템에 앱을 설치해야 합니다. 앱 패키지를 생성하고 테스트 시스템에 설치할 때 응용 프로그램 패키지를 로컬로 공유하기 위해 Visual Studio를 사용하는 것이 좋습니다. 이 옵션에서 Visual Studio는 적절한 인증서, 라이선스, 종속성 패키지, 그리고 앱 패키지 자체를 설치하는 PowerShell 스크립트와 함께 모든 관련 파일이 포함된 폴더를 생성합니다. 응용 프로그램 패키징 작업은 수동으로 수행해야 하지만, 설치는 PowerShell을 기반으로 이루어지며 자동화가 가능합니다. 설치 과정은 다음과 같습니다.

1단계:

PowerShell 스크립트 실행을 사용하도록 설정합니다. 보안상의 이유로 기본 PowerShell 실행 정책은 PowerShell 스크립트의 실행을 제한하므로 이 정책을 재정의해야 하며, 사용자의 조작이 필요하기 때문에 수동으로 진행해야 합니다. 다행히 이 작업은 컴퓨터별로 한 번씩만 수행하면 됩니다. 권한이 승격된 PowerShell 창에서 이 명령을 실행하여 PowerShell 스크립트 실행을 사용하도록 설정합니다.

PS C:\> Set-ExecutionPolicy AllSigned
 Powershell_admin
그림 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단계:

개발자 라이선스를 획득합니다. 이 단계는 사용자의 조작이 필요하기 때문에 수동으로 진행해야 합니다. 하지만 라이선스의 유효 기간 동안 컴퓨터마다 한 번씩만 수행하면 됩니다. 테스트 시스템에 이미 개발자 라이선스가 있으면 이 단계는 건너뜁니다.

UAC 프롬프트를 수락하고 지시에 따라 개발자 라이선스를 획득합니다. 아래 스크린샷을 통해 작업이 어떻게 진행되는지 알 수 있습니다.

첫 번째 스크린샷에서는 개발자 라이선스를 설치하기 위한 라이선스 조건에 동의하는지 여부를 묻고 있습니다. 계속 진행하려면 [동의]를 클릭합니다.

Powershell_devlic

그림 3: 개발자 라이선스 획득 프롬프트를 수락한 경우

[Microsoft 계정] 대화 상자에 자신의 Microsoft 계정을 입력합니다. Microsoft 계정이 없으면 [등록]을 클릭하여 계정을 만듭니다.

msaccount_signin

그림 4: Microsoft 계정 로그인 자격 증명으로 로그인한 경우

그러면 개발자 라이선스가 생성되었음을 확인해 주고 라이선스의 만료 날짜를 알려주는 메시지를 받게 됩니다.

devlic_approve

그림 5: 개발자 라이선스를 성공적으로 획득한 경우

다음 스크린샷은 개발자 라이선스를 획득했으며 패키지가 성공적으로 설치되었음을 보여줍니다.

PS_packagesuccess

그림 6: 설치를 완료한 경우

앱 활성화의 자동화

이제 테스트 시스템에 앱 패키지 설치가 완료되었고 앱을 실행할 준비가 되었습니다. IApplicationActivationManager 인터페이스로 앱의 활성화를 자동화할 수 있습니다. 이 API는 Visual Studio 2012와 함께 기본 설치되는 Windows SDK에 포함되어 있습니다. 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는 앱의 고유한 식별자 역할을 합니다. AppUserModelId를 검색하려면 PowerShell을 사용하는 것이 좋습니다. 컴퓨터에 설치한 모든 앱의 AppUserModelId를 검색하는 방법은 다음 PowerShell 스크립트를 참조하세요.

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

또한 IAppxManifestReader를 사용하여 패키지에 있는 앱을 열거하고 IAppxManifestApplication::GetAppUserModelId 메서드를 사용하여 AppUserModelId를 얻을 수도 있습니다. 하지만 테스트 중인 하나의 앱에 주안점을 둔다면 앱 매니페스트를 읽는 도구를 작성하는 것보다는 레지스트리를 사용하는 것이 훨씬 간단합니다.

앱의 핵심 기능 자동화

이제 앱이 테스트 시스템에 설치되었고 자동화된 환경에서 앱을 실행할 수 있습니다. 다음 단계는 앱의 핵심 기능에 대한 테스트를 자동화하는 것입니다. 단위 테스트와 더불어, UI 자동화의 사용자 인터페이스를 통해 앱을 자동화함으로써 이를 달성할 수 있습니다.

단위 테스트와 UI 자동화를 함께 사용할 경우 보다 광범위하게 테스트할 수 있으며, 이 상호 보완적인 기술을 통해 앱의 품질을 높일 수 있습니다. 단위 테스트를 사용하면 앱 내에서 핵심 비즈니스 논리를 자동화할 수 있습니다. UI 자동화 테스트에서는 사용자 인터페이스의 사용을 시뮬레이션하여 앱의 기능을 검증할 수 있습니다. 이러한 방법들을 결합하면 더욱 광범위하게 앱을 테스트할 수 있습니다.

그럼 각 방법에 사용되는 도구와 기술에 대해 설명하겠습니다.

단위 테스트

단위 테스트는 앱의 핵심 기능을 검증할 수 있는 강력한 기술입니다. Visual Studio 2012에서는 C# 또는 C++로 작성된 앱을 위한 구성 단위 테스트를 지원합니다. Visual Studio 2012에서 단위 테스트를 생성하고 실행하는 방법에 대한 자세한 내용은 단위 테스트 생성 및 실행을 참조하세요. 이미 다른 단위 테스트 프레임워크에 익숙한 경우에는 해당 프레임워크를 Windows 스토어 앱 단위 테스트에도 계속 사용할 수 있습니다.

UI 자동화

단위 테스트는 앱의 내부 동작 테스트에는 유용하지만 앱의 사용자 인터페이스를 실행할 수는 없으므로 UI 자동화(UIA)의 사용자 인터페이스를 통해 앱의 기능을 검증하는 것이 좋습니다.

Windows 8 보안 모델의 경우 앱에는 UI 자동화 클라이언트가 되기 위해 필요한 권한이 없습니다. 하지만 앱을 대상으로 자동화 클라이언트 역할을 하는 데스크톱 앱을 작성할 수는 있습니다. 이 작업을 수행하려면 UI 자동화 보안 개요에서 설명했듯이 데스크톱 자동화 클라이언트 앱을 UIAccess 권한으로 빌드해야 합니다.

Windows SDK에는 UI 자동화 클라이언트의 좋은 예제가 포함된 Inspect.exe 및 AccEvent.exe와 같은 몇 가지 도구를 제공합니다. Inspect를 사용하면 두 종류의 앱에서 모두 UI 자동화 트리를 검사할 수 있습니다. 한편 AccEvent를 통해 UIA 이벤트를 확인할 수 있습니다. Windows SDK가 설치되어 있는 컴퓨터에서는 보통 이러한 도구가 %ProgramFiles(x86)%\Windows Kits\8.0\bin\<architecture>에 속해 있습니다. 다음은 두 도구가 작동하는 모습입니다.

inspect.exe

그림 7: Bing 뉴스 앱에서 실행 중인 Inspect 도구

accevent_tool

그림 8: Bing 스포츠 앱에서 실행 중인 AccEvent 도구

이 도구들의 사용 방법과 마찬가지로, 앱을 자동화하는 데스크톱 클라이언트 앱을 작성할 때 UIA를 사용할 수 있습니다. UIA 클라이언트를 구축하는 방법을 익히려면 C++와 C#의 UI 자동화 클라이언트 앱 구축이란 제목의 글을 먼저 읽어보는 것이 좋습니다. 이 글에서 다룬 내용은 기존의 UI 자동화와 관련된 것이지만 여기에 소개된 기술은 모든 앱에 적용할 수 있습니다.

UI 자동화 문서 콘텐츠 클라이언트 샘플에는 UIA 컨트롤 패턴을 사용하여 대상 앱의 창에서 헤더, 댓글, 현재 선택 문서 등 다양한 종류의 콘텐츠를 검색하는 방법이 제시되어 있습니다. 터치 입력 주입 샘플에는 터치 입력 주입 API를 사용하여 앱을 검증하기 위해 터치를 시뮬레이션하는 방법이 설명되어 있습니다.

앞서 언급한 바와 같이 단위 테스트와 UI 자동화는 앱 내에 있는 핵심 비즈니스 논리와 사용자 인터페이스에서 실행되는 기능을 모두 자동화할 수 있는 상호 보완적인 기술입니다. 이러한 기술을 모두 사용하여 앱을 디버깅하기 바랍니다.

앱의 수명 주기 상태 자동화

라이브 앱을 위한 앱 수명 주기 관리에서 개략적으로 설명한 것과 같이 앱은 다양한 런타임 상태로 변경될 수 있습니다. 테스트 관점에서 보면 이 모든 상태에서 앱을 검증하는 것이 매우 중요합니다. 앱의 수명 주기 상태 변경을 자동화하는 데 사용할 수 있는 명령줄 도구인 Windows용 디버깅 도구와 함께 구입할 수 있는 도구(PLMDebug)를 사용하여 이러한 상태 변경을 자동화할 수 있습니다.

PLMDebug가 적합하지 않을 경우에는 IPackageDebugSettings 인터페이스를 사용하여 앱의 수명 주기 상태를 변경할 수 있는 자신만의 도구를 구현할 수도 있습니다. 이 API는 Visual Studio 2012와 함께 기본 설치되는 Windows SDK에 포함되어 있습니다. 이 코드는 IPackageDebugSettings API를 사용하여 앱의 수명 주기 상태를 변경하고 이러한 상태 변환 과정에서 예상대로 앱이 작동하는지를 검증하는 방법을 보여줍니다.

#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이 필요합니다. 따라서 다음 예제에 나타난 것과 같이 Get-AppxPackage PowerShell cmdlet를 사용하여 PackageFullName을 검색하는 것이 좋습니다(쉽게 읽을 수 있도록 요약된 결과).

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 cmdlets 특히, 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

결론

지금까지 앱 테스트를 자동화하는 데 사용되는 몇 가지 팁, 도구 및 기술에 대해 설명했습니다. 자동화 테스트는 앱의 검증 수준과 품질을 높일 수 있는 비용 대비 효과가 뛰어난 방법입니다. 하지만 앱 검증 작업에 인적 요소를 제공할 수 있는 수동 테스트 역시 검증 작업에 있어 중요한 역할을 합니다. 따라서 자동화 테스트와 수동 테스트를 결합하면 앱을 균형있게 테스트할 수 있습니다.

- Windows 테스트 책임자, Ashwin Needamangala

이 블로그 글을 작성하는 데 도움을 준 분들, 특히 Mete Goktepe, J. Kalyana Sundaram, Ben Betz, Will Wei, Chris Edmonds, Craig Campbell, Jake Sabulsky에게 감사드립니다.

  • Loading...
Leave a Comment
  • Please add 5 and 7 and type the answer here:
  • Post