2012年10月4日木曜日

MsBuildでWindows Phone のビルドとテストを自動化


MsBuildって便利ですね しみじみ

自動化は男のロマン。

と言うことで、WindowsPhoneプロジェクトの

-ビルド
-テスト
-結果の回収

を自動で行おうと思います。ゆくゆくは、Jenkinsを利用したCIへと繋がります。

今回は、http://blogs.msdn.com/b/francischeung/archive/2012/01/03/running-windows-phone-unit-tests-via-msbuild.aspx

の内容ホボそのまま。

一連の自動化の流としては
1.ビルド実行
2.エミュレーターへのインストール
3.テスト実行
4.テスト結果を エミュレーターの分散ストレージに保存
5.テスト結果をローカルにコピー

1.プロジェクトを作る

作りましょう

2.テストプロジェクトを作る

以前の投稿 http://numa08.blogspot.jp/2012/09/windowsphonerx_19.html や、@okazuki さんの

http://d.hatena.ne.jp/okazuki/20110911/1315724390

あたりを参考にテストプロジェクトを作りましょう。

3.ログをファイルに出力する

ファイルと言っても、エミュレーター上の分散ストレージです。

テストプロジェクトに次のコードを追加します。

その上で、テストプロジェクトのMainPage.xaml.csを次のように変更します。

4.MsBuildタスクのプロジェクトを作る

ソリューションに新しい VisualC# クラスライブラリ を作成します。

参照に、
Microsoft.Build
Microsoft.Build.Engine
Microsoft.Build.Framework
Microsoft.Build.Task.v4.0
Microsoft.Build.Utilities.v4.0

を追加。次に、
"C:\Program Files (x86)\Common Files\microsoft shared\Phone Tools\CoreCon\10.0\Bin\Microsoft.Smartdevice.Connectivity.dll"

を参照に追加します。

5.タスクを書く。

MsBuildって本当に強力だなぁとしみじみ。

ぶっちゃけ、次のコードのコピペで動きますけど、もっともっとカスタマイズすると楽しいと思います。

using System;
using System.Linq;
using Microsoft.Build.Utilities;
using Microsoft.SmartDevice.Connectivity;
using System.Threading;
using System.Globalization;
using System.IO;
using Microsoft.Build.Framework;
namespace MyMsBuildTask
{
public class RunWP7UnitTestsInEmulator:Task
{
private int defaultNumberOfMiliSecondsToProcess = 50000;
[Required]
public string PathToUnitTestXapFile { get; set; }
[Required]
public string ProductGuid { get; set; }
public int NumberOfMilliSecondsToProcess { get; set; }
public override bool Execute()
{
if (NumberOfMilliSecondsToProcess == 0)
{
Log.LogMessage(string.Format("Using default processing time: {0}", defaultNumberOfMiliSecondsToProcess));
NumberOfMilliSecondsToProcess = defaultNumberOfMiliSecondsToProcess;
}
Log.LogMessage(string.Format("NumberOfMilliSecondsToProcess: {0}", NumberOfMilliSecondsToProcess));
Log.LogMessage("Running tests in XAP: " + PathToUnitTestXapFile);
var productGuid = new Guid(ProductGuid);
var emulator = GetWP7Emulator();
Log.LogMessage("Connecting to Emulator.");
emulator.Connect();
Log.LogMessage("After call to Connect().");
//Deploy application
if (emulator.IsApplicationInstalled(productGuid))
{
emulator.GetApplication(productGuid).Uninstall();
}
emulator.InstallApplication(productGuid, productGuid, "NormalApp", null, PathToUnitTestXapFile);
//Run application
var application = emulator.GetApplication(productGuid);
application.Launch();
Thread.Sleep(NumberOfMilliSecondsToProcess);
//Get Results from Isolated Store on device
var isostorefile = application.GetIsolatedStore();
var localTestResultFileName = "EmulatorTestResults-" + productGuid + ".txt";
isostorefile.ReceiveFile(@"\TestResults\testresults.txt", localTestResultFileName, true);
var testResults = File.ReadAllText(localTestResultFileName);
if (testResults.Contains("Exception:"))
{
Log.LogError("Failing test found. Look for exception in: " + localTestResultFileName);
return false;
}
Log.LogMessage("All tests passed.");
emulator.Disconnect();
return true;
}
private Device GetWP7Emulator()
{
var manager = new DatastoreManager(CultureInfo.CurrentUICulture.LCID);
var wp7Platform = manager.GetPlatforms().Single(platform => platform.Name == "Windows Phone 7");
return wp7Platform.GetDevices().Single(device => device.Name == "Windows Phone Emulator(JA)");
}
}
}


6.MsBuildファイルを書く

こちらは、テストプロジェクトのUUIDやファイルパスなどを指定する必要があります。

さっき作ったprojファイルから見た相対パスらしいので、それに合わせてxapファイルのパスを適切に設定します。

ProductGuidはテストプロジェクトの WMAppManifest.xml のAppタグOriductIDの値を使います。

<?xml version="1.0" encoding="utf-8" ?>
<Project DefaultTargets="Test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" >
<UsingTask TaskName="MyMsBuildTask.RunWP7UnitTestsInEmulator"
AssemblyFile="MyMsBuildTask.dll"/>
<PropertyGroup>
<SourceFilesPath>$(MSBuildProjectDirectory)</SourceFilesPath>
</PropertyGroup>
<ItemGroup>
<SolutionItemsToBuild Include="$(SourceFilesPath)\**\*.sln" />
</ItemGroup>
<Target Name="Build">
<MSBuild Projects="%(SolutionItemsToBuild.Identity)" Targets="Build"/>
</Target>
<Target Name="Test" DependsOnTargets="Build">
<RunWP7UnitTestsInEmulator NumberOfMilliSecondsToProcess="50000"
PathToUnitTestXapFile="$(SourceFilesPath)\(your test project).xap"
ProductGuid="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" />
</Target>
</Project>
view raw msbuild.proj hosted with ❤ by GitHub

7.実行する

エミュレーターを立ち上げた状態で MsBuild msbuild.proj としてやれば、自動的にプロジェクトのビルドと、
テストの実行が走ります。

最後に、EmulatorTestResult-$(GUID)-.txtが吐き出されていれば成功。



何が凄いって、テストに失敗するとテストに失敗すると、例外を検知してMsBuildが失敗を返すところ。

これは便利です。Jenkinsの場合、ビルドの成功失敗は取れてましたけど、テストの成功失敗は別で管理してました。

あー、でもこのテストの失敗は無視ー とかそういう状態も発生するわけか。まあ、その辺はタスクのカスタムでなんとかなるんだと思います。


思いますよ。そのうちやります。

0 件のコメント:

コメントを投稿