Testen von Windows-Phone-8.1-Anwendungen

Kleine Kachel, große (Test-)Welt
Kommentare

Eine App mag zwar einen enger gesteckten Anwendungsbereich haben als die großen, trägen Anwendungen aus der Desktopgeneration, aber zwingend weniger komplex ist ihre Entwicklung deshalb nicht. Der klassische Anwendungszyklus aus Spezifikation, Design, Entwicklung, Test und Auslieferung findet genauso wie bei den großen Brüdern und Schwestern statt. Die mobile Entwicklung ist sogar aufgrund der vielen Formfaktoren, geringeren Hardwareressourcen, der hohen Releaseanzahl und der Konkurrenz in den App Stores herausfordernder. In diesem Artikel möchten wir uns deshalb mit dem Thema der Qualitätssicherung von mobilen Apps für Windows Phone 8.1 beschäftigen.

Bei der Entwicklungstechnologie einer App hat man die Qual der Wahl, wobei jede Entscheidung des Entwicklers auch direkte Auswirkungen auf die Arbeit der Tester hat. Gerade die Automatisierungsmöglichkeiten werden dadurch entweder massiv eingeschränkt oder vergrößert. In der Windows-Phone-App-Welt stehen im Grunde genommen vier Technologien zur Auswahl: JavaScript- bzw. Webtechnologien, C++, Windows Phone Silverlight 8.1 und Windows Phone (WinRT).

Beim ersten Typ gehören Frameworks wie PhoneGap oder Apache Cordova zum Standardrepertoire der Entwickler. Aus Testsichtweise ist man hier mit Visual Studio primär auf Unit Testing beschränkt. Scheut man sich nicht vor anderen Tools, wäre der Ripple Emulator für Chrome eine Alternative. Diese Extension bildet das Verhalten und die Hardware eines mobilen Gerätes im Desktopbrowser nach. Auch beim zweiten und dritten Typ sind die Testmethoden primär Unit Testing und manuelles Testen. Beim vierten Typ hingegen stehen Ihnen alle Testing-Wege offen: neben den Unit und Integrationstests wird auch UI-basiertes Testen unterstützt.

Zu guter Letzt gibt es noch die Universal-Apps, eine Kombination aus zwei plattformspezifischen App-Typen sowie Code-Sharing-Projekten. Als Testmethoden sind hier alle bereits bekannten Testmethoden aus der Windows- und Windows-Phone-Welt möglich: das Unit/Integration und UI Testing. Die besondere Herausforderung hier ist, auch beim Testen möglichst viel Code für beide Plattformen wiederverwenden zu können.

Testinfrastruktur

Microsoft bietet zum Testen und Entwickeln verschiedene Entwickler-Images zur lokalen Installation an, die sich in Betriebssystemversion und Formfaktor unterscheiden. Als Basis für die diversen Windows Phone Images dient Hyper-V – dementsprechend müssen die Entwicklungs- und Test-PCs Hyper-V-fähig sein und mindestens Windows 8 bzw. Windows Server 2012 als Hostsystem mitbringen. Aus diesem Grund ist das Entwickeln in einer Azure VM aktuell (noch) nicht möglich. Das virtuelle Phone Image bringt viele aus der Virtualisierungswelt bekannte Funktionalitäten mit, z. B. Snapshots. Dazu kommen unter anderem die Emulation von Mobile-Hardware wie GPS, ein Beschleunigungssensor, eine Kamera, ein Netzwerk, eine SD-Karte oder ein Lichtsensor. Die CPU-Architektur ARM wird allerdings nicht direkt nachgebildet. Alle Tests werden aufgrund von Hyper-V nur in einer x86-basierenden CPU ausgeführt. Vorteilhaft ist an diesem Konzept, dass der Emulator im Gegensatz zu Windows-Mobile-Zeiten relativ schnell ist. Aufgrund dieser Besonderheit in der CPU-Architektur sind die Images aber nur für funktionale Tests geeignet. Muss die App bestimmte Performancekennzahlen einhalten, ist ein Test auf unterschiedlicher Hardware mit verschiedenen Leistungsdaten zwingend als weitere Teststufe notwendig.

Bei den Testframeworks hat Microsoft an die Unterstützung von echter Hardware gedacht. Sowohl Unit als auch UI-Tests lassen sich direkt auf physischen Geräten ausführen. Der manuelle Testaufwand kann also auch bei sehr vielen verschiedenen Geräten zu einem Großteil automatisiert werden. Um ein physisches Gerät mit eigenen Apps und Tests zu versehen, ist als erster Schritt dessen Freischaltung als Entwicklergerät notwendig. Danach können Sie beliebige Apps auf das Gerät ausrollen und dort sogar direkt debuggen. Voraussetzung zur Freischaltung ist eine Entwicklerregistrierung – für MSDN-Abonnenten ist diese kostenlos, andernfalls fällt eine Jahresgebühr in Höhe von 14 Euro an. Für die virtuellen Entwickler-Images ist eine Registrierung hingegen nicht notwendig. Automatisierte Tests können über Visual Studio im Emulator oder die Kommandozeile (vstest.console.exe) auf einem physischen Gerät ausgeführt werden. VSTest.Console ist die Kommandozeilenversion des neuen Visual-Studio-Testexplorers. Als Konsequenz werden auch fremde Testframeworks bei entsprechend installierten und unterstützten Testadaptern unterstützt. Um Tests auf einem physischen Gerät auszuführen, ist die Angabe einer Runsettings-Datei notwendig, die die Laufzeitumgebung des Testrunners konfiguriert:



  
    
    Device
    
    
  

Abb. 1 zeigt die Ausführung über die Kommandozeile mit der Generierung von importfähigen Visual-Studio-Testergebnissen (TRX). Damit die Ausführung auf dem Gerät funktioniert, muss dieses per USB mit dem Test-/Entwickler-PC verbunden sein.

Abb. 1: Ausführen von Tests auf einem physischen Gerät

Testmanagement

Ein Testprozess, egal, ob wir über klassische oder mobile Anwendungen reden, ist laut ISTQB (International Software Testing Qualifications Board) in fünf Prozessschritte eingeteilt: Planung und Steuerung, Analyse und Design, Realisierung und Durchführung, Auswertung und Bericht sowie Abschluss. In der Visual-Studio-Welt lassen sich alle Phasen durch TFS, VS, MTM und Office (Word, Excel, Project) abdecken. Dabei ist der MTM im Bereich Testmanagement das primäre Werkzeug. Auch vor dem Testen von Mobilanwendungen sollte ein Testplan mit allen zu berücksichtigenden Test- bzw. Anwendungsfällen erstellt, geplant und priorisiert werden. Nur wenn eine entsprechende Planung existiert, können die richtigen Bereiche getestet und Ressourcen geplant werden. Die Phase der Realisierung und Durchführung findet je nach Testmethode in zwei verschiedenen Werkzeugen statt. Die manuelle Testausführung erfolgt im MTM, der dem Tester die einzelnen Testschritte und das erwartete Ergebnis anzeigt. Wird dieses nicht erreicht, können Bugs direkt im TFS erfasst werden. Wird der MTM in Kombination mit Windows Phone eingesetzt, ist die Erfassung von Rich Bugs beim Einsatz von Diagnoseadaptern minimal eingeschränkt: Aufgrund des fehlenden direkten Zugriffs funktionieren die Adapter für Event Logs, Action Recordings, IntelliTrace und Test Impact nicht. Sinnvoll einsetzen lassen sich hingegen die Diagnoseadapter Video und Voice Recording und Screenshots. Sie ermöglichen, den aktuellen Bildschirminhalt in Videoform aufzuzeichnen. Die Aufzeichnung einer Anwendung im Emulator ist kein Problem, weil dieser als Windows-Anwendung läuft. Möchten Sie hingegen eine Videoaufzeichnung eines Hardwaredevices anfertigen, können Sie den Bildschirminhalt Ihres Windows Phone über Software Beam auf Ihren Desktop projizieren, sodass er für den MTM sichtbar wird. Mit dieser Methode können Sie Fehler reproduzierbar im TFS in Bug Work Items ablegen.

Neben der Videoaufzeichnung sind für das manuelle Testen noch die Windows Phone Developer Power Tools interessant. Dieses Werkzeug macht Performancewerte aus dem Emulator und vom Gerät auslese- und auswertbar. Zu den Kennzahlen zählen z. B. Speicher, CPU und Grafikkartenaktivität.

[ header = Seite 2: UI Testing ]

UI Testing

Das Testen von Oberflächen kann über das Framework Coded UI realisiert werden. Es unterstützt beispielsweise WPF, WinForms, Windows-Store- und Webanwendungen und seit Visual Studio 2013 Update 2 auch Windows-Phone-Apps. Ähnlich wie bei Windows-Store-Apps erfolgt auch hier eine Limitierung auf XAML-basierte Anwendungen. Die anderen App-Typen wie Silverlight-, HTML- und C++-Apps werden aktuell nicht in Coded-UI-Tests unterstützt. Als Alternative bleibt hier nur der Weg über Unit/Integration Tests auf Codeebene sowie manuelles UI Testing.

Bevor man mit dem Schreiben von UI-Tests beginnt, sollte die Anwendung auf ihre Tauglichkeit für solche Tests untersucht werden. Coded UI funktioniert für XAML-Apps auch ohne große Optimierungen – die Erfahrung hat allerdings gezeigt, dass Unzufriedenheit mit Coded UI in den meisten Fällen auf fehlende Optimierungen zurückzuführen ist. Bei Phone-Apps sind, genauso wie bei den Store- und WPF-Apps, die AutomationProperties AutomationId und Name aus der Accessibility-Schnittstelle UIA von großem Interesse. Über diese Properties können Controls auf der Oberfläche eindeutig identifiziert werden. Setzt der Entwickler diese Eigenschaften nicht, führen alle Controls automatisch eine Fallback-Strategie aus: der jeweils angezeigte Control-Text wird automatisch zu AutomationId bzw. Name. Problematisch wird dies, wenn z. B. DisplayTexts lokalisiert sind oder sich anderweitig dynamisch setzen. Das bewusste Zuweisen der AutomationProperties kann entweder mittels Blend oder manuell im XAML-Markup-Code geschehen. Der Vorteil einer automatischen Zuweisung per Blend besteht darin, dass alle Controls mit wenig Aufwand zugewiesen werden können. Die Namen sind allerdings nicht wirklich sprechend. Besser für eine langfristige Wartbarkeit ist die manuelle Zuweisung, denn manuell zugewiesene Namen sind sprechender, und der darauf aufbauende Code ist zwecks Wartbarkeit und Verständnis wesentlich besser lesbar. Der folgende Code zeigt ein Beispiel aus der 7Pass-App für optimierte Controls:

// Datei: EntryFieldValue.XAML
// TextBox mit UIA Properties
...


// ToggleSwitch mit UIA Properties

...

Nachdem unsere App mit AutomationProperties vorbereitet ist, geht es an das Schreiben der Tests. Visual Studio bietet standardmäßig als Erstes die Erstellung von UIMaps mit dem Coded UI Test Builder an. Eine UIMap ist eine generierte .NET-Bibliothek mit Klassen zum Ansteuern von UI-Controls und -Methoden zum Ausführen und Prüfen.

Eine bessere Möglichkeit zum Aufbau von UI-Test ist, den Code für das UI-Test-Framework manuell zu schreiben. Dieser selbstgeschriebene Code hat den Vorteil, dass die Redundanz des Codegenerators vermieden und die Wartbarkeit durch Wiederverwendbarkeit erhöht wird. Gleiche Logik und Einstellungen können einfach in zentralen Klassen ausgelagert werden. Ändert sich die UI-Struktur der App, müssen nur wenige Stellen angepasst werden. Den Beginn markiert die Klasse BaseUIObject, in der wir allgemeingültige, übergreifende Logik ablegen. Im Beispiel unserer App „7Pass“ wären dies z. B. generische Methoden zum Ansteuern der Textboxen, das Auslösen der Hardwarebuttons (Suche-, Zurück-, Windows-Button) oder das Umschalten der Hub-Sichten (Listing 1). Die Klasse BaseUIObject wird im nächsten Schritt von den spezifischen UI-Objekten für die einzelnen Szenarien, Views oder Fenster abgeleitet. Die UIObject-Strategie hängt letztendlich von der jeweiligen Anwendung ab. Am Beispiel der 7Pass-Anwendung ergeben sich exemplarisch CommonUI, PasswordEntryUI, PasswordEntryDetailsViewUI, PasswordEntryAttachmentsViewUI, PasswordEntryFieldsViewUI und PasswordEntryNotesViewUI.

public class BaseUIObject
{
  // Eigenschaft um zentral eine Referenz auf das App Fenster zu halten
  public XamlWindow AppWindow { get; set; }
  // Generische Methoden zum Finden von Controls auf Basis des UIA Automation Namen
  public T FindXamlControlByName(UITestControl rootControl, string name, bool searchByFrameworkId = true) where T : XamlControl, new()
  {
    var xamlControl = new T { Container = rootControl };
    xamlControl.SearchProperties.Add(XamlControl.PropertyNames.Name, name);
    if (searchByFrameworkId)
    xamlControl.SearchProperties.Add(XamlControl.PropertyNames.FrameworkId, "UIX");
    return xamlControl;
  }
  // Generische Methoden zum Finden von Controls auf Basis des UIA Automation ID
  public T FindXamlControlById(XamlControl rootControl, string automationId, bool searchByFrameworkId = true) where T : XamlControl, new()
  {
    // ...
  }
  // Generische Methoden zum Finden von Controls auf Basis der Framework ID
  public T FindXamlControlByFrameworkId (XamlControl rootControl, string frameworkId) where T : XamlControl, new()
  {
    // ... 
  }

  // Zurück Hardware Button auslösen
  public void PushGoBackButton()
  {
    Device.HardwareButton.Back();
  }
  // Start Hardware Button auslösen
  public void PushStartButton()
  {
    Device.HardwareButton.Start();
  }
...
}

In der CommonUI-Klasse sind anwendungsspezifische übergreifende Aktionen ablegt, z. B. StartApp, StopApp, OpenPasswordFile, AddPasswordFile, SelectFolder und SelectEntry (Listing 2). Als Nächstes steht die Implementierung der spezifischen UI-Objekte für die diversen Hub-Sichten an. Ein Passworteintrag in 7Pass enthält vier Hub-Sichten. Aus diesem Grund legen wir noch eine UIObject-Klasse (PasswordEntryUI) für einen Passworteintrag mit Navigationslogik für das Umschalten der Sichten an. In Form von Methoden sind dies GoToDetailsView, GoToNotesView, GoToAttachmentsView und GoToFieldsView (Listing 3). Interessant dabei ist der Einsatz von Gesten zum Umschalten der Views, was hier per Swipe-Geste von links nach rechts erledigt wird. In Windows-Store- und Windows-Phone-Apps können diverse Gesten per Gesture-Klasse gesteuert werden.

// App starten
XamlWindow myAppWindow = XamlWindow.Launch("My App GUID");
public class CommonUI : BaseUIObject
{
  public XamlControl Window { get; set; }

  // Starten einer App auf Basis der AutomationID
  // AutomationID wurde mit dem CodedUI TestBuilder ermittelt
  public void StartApp()
  {
    AppWindow = XamlWindow.Launch("{9784297B-2DBB-49A2-8247-19A3756BBD20}:App:9784297b-2dbb-49a2-8247-19a3756bbd20_p01659jmcbgp6!App");
  }
  // Schliessen der gestarteten App
  public void CloseApp()
  {
    if (null != AppWindow)
    AppWindow.Close();
  }

  // Eine Passwort Datei in 7Pass hinzufügen
  // Dialog ist mehrstufig
  public void AddPasswordFile()
  {
    // App Fenster finden
    Window = FindXamlControlByFrameworkId(XamlWindow.Desktop, "UIX");
    // Add Button auslösen
    var addButton = FindXamlControlByName(Window, "add");
    // Windows Phone kennt keine Maus Aktion, sondern nur Gesten
    // Tap ist die Windows Phone Version eines Mausklicks
    Gesture.Tap(addButton);

    // Dialog schaltet um -> Phone auswählen
    var selectStorage = FindXamlControlByName(Window, "Phone");
    Gesture.Tap(selectStorage);
    // Dialog schaltet um -> SD Karte als Ordner auswählen
    var selectFolder = FindXamlControlById(Window, "KnownFoldersList", false);
    var selectSDCard = FindInListByLabelText(selectFolder, "sd card");
    Gesture.Tap(selectSDCard);

    // Dialog schaltet um -> Datei NewDatabase.kdbx auswählen
    // Mehrstufiges suchen notwendig, weil 7Pass noch nicht auf jeder Ebene AutomationId eingeführt hat
    // Suche nach ListItem Control auf Basis des Label Textes
    var folderContentsListView = FindXamlControlById(Window, "PART_FolderContentsListView", false);
    var folderViewContentGroup = FindXamlControlByName(folderContentsListView,
    "Microsoft.Phone.FileManager.ViewModels.FolderViewContentGroup", false);
    foreach (var fileGroupChildControl in folderViewContentGroup.FindMatchingControls())
    {
      var fileEntry = FindInListByLabelText(fileGroupChildControl, "NewDatabase.kdbx");
      Gesture.Tap(fileEntry);
    }
  }

  // Öffnen einer hinzugefügten Passwort-Datei
  public void OpenPasswordFile()
  {
    // App-Fenster finden
    Window = FindXamlControlByFrameworkId(XamlWindow.Desktop, "UIX");

    // Liste mit Keepass-Dateien finden
    var databasesList = FindXamlControlById(Window, "Databases", false);

    // Gewünschte Datei auswählen
    var selectDB = FindInListByLabelText(databasesList, "NewDatabase");
    Gesture.Tap(selectDB);

    // Dialog schaltet um -> Passwort eingeben
    var passwordBox = FindXamlControlById(Window, "Password", false);
    passwordBox.Text = "test";

    // Eingabe durch Drücken von Öffnen bestätigen
    var openButton = FindXamlControlByName(Window, "open");
    Gesture.Tap(openButton);
  }
...
}
public class PasswortEntryUI : BaseUIObject
{
  public XamlControl Window { get; set; }

  public void GoToDetailsView()
  {
  // App-Fenster suchen
  Window = FindXamlControlByName(XamlWindow.Desktop, "7Pass Remake", false);
  // Passwortdatei Hub-View suchen
  var newDatabaseHub = FindXamlControlByName(Window, "NewDatabase", false);
  // Details-Label suchen
  var detailsLabel = FindXamlControlByName(newDatabaseHub, "Details", false);
  // IsVisible ist eine eigene Extension-Methode
  // Auf Basis der Koordinaten wird entschieden, ob die Hub-View im sichtbaren Bereich ist
  if (!detailsLabel.IsVisible())
  {
    // Die maximale Anzahl an Swipes ist abhängig von der Anzahl an Hub Views
    for (int i = 0; i < newDatabaseHub.GetChildren().Count; i++)
    {
      // Auslösen der Swipe-Geste in die linke Richtung mit der Länge 200px auf dem ersten Element des App-Fensters
      Gesture.Swipe(Window.GetChildren()[0], UITestGestureDirection.Left, 200);
    }
  }
...
}

Nun steht die Umsetzung der Views als UI-Objekte an. Am Beispiel der PasswordEntryDetailsViewUI wären Methoden wie EnterUserName, CheckUserName, EnterPasswort, ChechPasswort, OpenBrowser und IsDetailsViewOpen sinnvoll. Ein Beispiel (CheckUserName) für eine automatische Prüfung mit Asserts finden Sie in Listing 4. Die UI-Tests können dann über den Visual-Studio-Testexplorer auf einem Emulator-Image oder einem Gerät zum Einsatz kommen.

public class PasswordEntryDetailsViewUI : BaseUIObject
{
  public XamlControl Window { get; set; }

  // Prüfe, ob Michael321 als Nutzername eingegeben wurde
  public bool CheckUserName()
  {
    // App-Fenster suchen
    Window = FindXamlControlByName(XamlWindow.Desktop, "7Pass Remake", false);
    // Passwortdatei Hub-View suchen
    var newDatabaseHub = FindXamlControlByName(Window, "NewDatabase", false);
    // Suche Username Textbox
    var userNameEditBox = FindXamlControlById(newDatabaseHub, "UserName", false);
    // Prüfe, ob Nutzername Michael321 in der Textbox vorkommt
    Assert.AreEqual("Michael321", userNameEditBox.Text);
    return true;
  }
  ...
}

[ header = Seite 3: Unit/Integration Testing ]

Unit/Integration Testing

Der UI-Test oder auch Systemtest ist die höchste Ebene in der Testpyramide. Die unterste Schicht stellen die Unit Tests dar, und dazwischen liegen die Integrationstests. Anders als beim UI-Test kennen wir hier die Applikationsimplementierung und führen also einen White-Box-Test durch. Entscheidend sind in der modernen Applikationsentwicklung neben einem ansprechenden GUI auch der App-Unterbau und eine gute Softwarearchitektur. Da diese mit der Entwicklung mitwächst, lautet das oberste Ziel, keinen Wildwuchs zu erhalten und den bestehenden Code mittels Refactoring auf die neuen Anforderungen hin anzupassen. Somit liegt es auf der Hand, auch im Mobile-Bereich einen Test-driven-Development-Ansatz (TDD) zu fahren und getreu dem Motto „Red Green Refactor“ die Arbeit voranzutreiben.

Egal, ob die App nur das Frontend für einen Backend-Service darstellt oder auch die Businesslogik sowie Persistenzschicht enthält, die Anforderungen an Schichtenarchitektur, Entkopplung und Modularisierung sind dieselben. Die Vorgehensweise und Patterns für qualitativ hochwertigen und einfach testbaren Code unterscheiden sich indes kaum von denen in der Windows-Applikationsentwicklung. Als Grundlage für den gesamten Code dient das Dependency-Injection-Pattern. Zu den Anfängen der Windows Runtime kaum denkbar, sind mittlerweile einige Dependency-Injection-Container-Implementationen für WinRT vorhanden, beispielsweise für Unity. Die Abhängigkeiten einer Klasse werden in Form von Interfaces definiert. Abb. 2 zeigt auf der linken Seite die Implementation des View Models, das die Abhängigkeiten mittels Constructor Injection definiert. Zur Laufzeit werden dann die konkreten Implementierungen vom Dependency-Injection-Container geliefert. Für Unit und Integrationstests eignen sich die Interfacedefinitionen der Abhängigkeiten ideal zum einfachen Isolieren der internen und externen Abhängigkeiten durch Stubs oder Mocks. Der Unit Test auf der rechten Seite zeigt die Instanziierung der Mocks sowie die eigentlichen Unit Tests.

Abb. 2: Windows Phone Unit Test mit Mocks

In der View-Logik gelten dieselben Prinzipien: Sie lässt sich einfach und effizient testen, wenn wir keine harten Referenzen zur Visualisierung haben. Anstatt die View-Logik in der Code-Behind-Datei zu implementieren, verwenden wir das MVVM-Pattern. Model View ViewModel (MVVM) entkoppelt hierbei die einzelnen Komponenten und verbindet sie über die Binding-Funktionalität von XAML. Somit können wir das View Model, das aus dem Laden und Validieren der Daten sowie der Implementation der Aktionen besteht, relativ einfach mittels eines Unit Tests überprüfen und müssen hierzu nicht einmal das UI hochfahren. Zur Implementierung des MVVM-Patterns empfehlen wir die Verwendung eines Frameworks. Die bekannte Bibliothek Prism steht neuerdings auch für XAML-basierte Windows-Runtime-Apps zur Verfügung. Als Alternative ist Caliburn.Micro zu erwähnen, das auch von unserer Demo-App 7Pass verwendet wird.

Um ein neues Unit-Test-Projekt zu erstellen, wird der entsprechende Projekttyp für die Windows-Phone-App ausgewählt. Die Vorlage erstellt ein Unit-Test-Projekt basierend auf MSTest. Bei xUnit wird derselbe Projekttyp verwendet, die Referenz auf das MSTest-Framework jedoch entfernt und das NuGet Packet „xunit“ mit Version 2.0 hinzugeführt (derzeit nur als Pre-Release verfügbar). Die gewählte Architektur sowie die definierten Module haben natürlich auch Einfluss auf die physikalische Codeverwaltung respektive Generierung der Assemblies. Für Windows-Phone-Apps können ebenfalls DLLs in Form von Class Libraries erzeugt werden. Vielmals ist aber gerade der Logikcode prädestiniert dazu, ausgelagert und in mehreren Apps übergreifend verwendet zu werden. Hier kann eine so genannte Portable Library zum Einsatz kommen. Abhängig von der ausgewählten Zielplattform ändert sich das zur Verfügung stehende API (Abb. 3).

Abb.3: Konfiguration einer Portable Library

Wird dieselbe Applikation als Windows-Store-App und Windows-Phone-App benötigt, kann der seit Visual Studio 2013 Update 2 zur Verfügung stehende Projekttyp „Universal App“ verwendet werden. Hierbei werden zwei plattformspezifische Applikationen erstellt und gemeinsamer Code in ein so genanntes Shared Code Project (*.shproj) ausgelagert. Was sich zunächst toll anhört, ist jedoch ein Problem für das Unit Testing. Ein Unit-Test-Projekt muss für die Windows- und Windows-Phone-App separat erstellt werden. Es ist nicht möglich, den geteilten Code direkt zu testen. Da wir selbstverständlich nur testbaren Code in unserem Projekt haben möchten, kommen wir also nicht drumherum, zwei Testprojekte zu erzeugen. Einen Shared Unit Test gibt es (noch) nicht. Auch bei Universal-Apps können Portable Libraries referenziert werden, die wiederum getestet werden können. Wenn nicht der vollständige zu testende Code in ein separates Assembly ausgelagert werden kann, wäre es trotzdem schön, analog zur Universal-App ein Shared Code Project für den Unit-Test-Code zu erhalten. Unsere Demo-App zeigt dies beispielhaft auf.

Abb. 4 zeigt die Projektstruktur unserer Beispiel-Applikation 7Pass. Der Großteil des Applikationscodes ist für beide App-Projekte im Shared Code Project „SevenPass.Shared“ implementiert. Wie erwähnt, müssen die beiden Apps jeweils separat mit einem Unit-Test-Projekt getestet werden. Um den Unit-Test-Code für die gemeinsam genutzten Klassen nicht zu duplizieren, wurde hierbei ein Shared Code Project verwendet. Dies ist im Standard noch nicht vorgesehen, kann aber entweder manuell in den Projektdateien nachgepflegt werden. Alternativ kann die Visual Studio Extension „Shared Project Reference Manager“ zum Einsatz kommen. Mit ihr lassen sich Shared Code Projects über die Projekttemplates erstellen und von anderen Projekten referenzieren. In unserem Beispielprojekt referenzieren jeweils die Projekte 1 und 2 das Shared Code Project 3, analog gilt das auch für Applikations- und Testprojekte.

Abb. 4: Projektstruktur und Shared-Unit-Test-Code

Fazit

Damit die Benutzung von Windows-Phone-Apps für den Kunden zum erfreulichen Erlebnis wird, ist die Qualitätssicherung eine sehr wichtige Komponente. Apps für Windows Phone lassen sich mittels verschiedener Frameworks implementieren, jedoch steht das komplette QA-Tooling inklusive UI-Automatisierung nur für XAML-basierte Windows-Phone-Apps zur Verfügung. Für die anderen App-Typen sind zumindest Unit-Test-Frameworks vorhanden. Mittels Automatisierung kann die Arbeit der Tester interessanter gestaltet werden, da die Routinetestfälle von der Automatisierung übernommen werden und sie primär neue oder sehr komplexe Anforderungen testen. In diesem Artikel haben wir gezeigt, dass sich auch im App-Bereich eine gute Architektur für stabilen und gut testbaren Code auszahlt. Viele WPF-Entwickler finden mittlerweile Portierungen ihrer verwendeten MVVM und Composite-Application-Frameworks für WinRT und können somit ihr Know-how einfach in die App-Welt übertragen.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -