Posts Tagged ‘Silverlight’

Automatisiertes Testen und Silverlight

Tuesday, May 11th, 2010

Silverlight ist inzwischen bei Version 4 angekommen und Microsoft bietet immer noch keine vernünftige Unterstützung für automatisierte Tests. Ja, ich weiß, es gibt das Silverlight Unit Test Framework aus dem Toolkit. Aber das ist, mit Verlaub, nicht praxistauglich. Dass Silverlight Code in der CoreCLR laufen muss und damit Unit Tests etwas aufwändiger zu realisieren sind, ist mir technisch völlig klar. Aber wieso drückt sich Microsoft davor, auf dem Gebiet seine Hausaufgaben zu machen? Wieso gibt es vom Hersteller selbst keine Unterstützung für Tests, die innerhalb von Visual Studio laufen? Wieso kann ich nicht per Knopfdruck einen einzelnen Test starten?

Die Arbeit mit Microsofts Silverlight Unit Test Framework ist lästig. Denn ich muss den Testrunner, der im Web-Browser läuft, mit Ctrl-F5 starten. Wenn ich mal Tests, mal die Silverlight Anwendung starten möchte, muss ich andauernd das Startproimagejekt ändern. Testgetriebene Entwicklung ist nur möglich, wenn ich einzelne Tests per Shortcut starten kann: einen Test schreiben, laufen lassen, rot. Implementieren, Test erneut laufen lassen, grün. Nächsten Test schreiben… Das alles geht nicht, solange der Testrunner im Browser läuft. Und wenn sich dann beim Start des Testrunners erst noch ein Popup öffnet, welches 5 Sekunden darauf wartet, ob ich möglicherweise nur Tests mit einem bestimmten Tag starten möchte, weiß ich, dass dieses Werkzeug definitiv nicht für die testgetriebene Entwicklung entworfen wurde. Schade.

Weiterhin halte ich es für sehr bedenklich, dass die Community sich nicht rührt. Wie testet ihr euer Silverlight Zeugs denn automatisiert? Garnicht?

Sorry für mein Lamentieren… aber ich verfolge das Thema nun schon seit Silverlight 1.1. Und seitdem hat sich nichts nennenswert verändert. Oder habe ich was übersehen?

Unit Tests mit Silverlight

Thursday, November 29th, 2007

Silverlight 1.1 bietet ein .NET Runtime so dass man in seiner gewohnten Programmiersprache entwickeln kann, für mich ist das C#. Ein weiteres liebgewordenes “Werkzeug” sind für mich Unit Tests. Ich will daher der Frage nachgehen, wie man Unit Tests realisieren kann für Code der unter Silverlight läuft. Das Beispiel habe ich mit VS2008 RTM und Silverlight 1.1 Tools Alpha erstellt.

Erste Voraussetzung dazu ist ein Unit Test Framework welches gegen die Silverlight Assemblies compiliert ist. Damit der Versuch nicht zu aufwendig wird habe ich dazu NUnitLite im Quelltext verwendet. Ferner bietet sich NUnitLite auch deshalb an da es explizit für Plattformen mit reduziertem Funktionsumfang konzipiert wurde.

Nach Download und Entpacken der NUnitLite Quellen habe ich mit VS2008 eine neue Solution mit einem Silverlight Projekt erstellt.

NUnitLiteSilver-1

Die Datei ‘Class1.cs’ habe ich anschließend entfernt und die NUnitLite Dateien in das Projekt übernommen. Dies geht recht einfach wenn man das Projekt NUnitLite.csproj in die Solution mit aufnimmt (VS2008 konvertiert das Projekt von VS2005 nach VS2008) und dann die benötigten Dateien und Verzeichnisse im Solution Explorer in das Silverlight Projekt kopiert.

NUnitLiteSilver-2

Nachdem man die NUnitLite Dateien in das Silverlight Projekt kopiert hat kann man das NUnitLite Projekt wieder aus der Solution entfernen. Ferner muss man die Datei AssemblyInfo.cs im Properties Ordner des Silverlight Projektes entfernen da sie sonst doppelt vorliegt.

Einem erfolgreichen Build steht nun (fast) nichts mehr im Weg. Folgende Änderungen sind am Quellcode vorzunehmen:

  1. In der Datei Assert.cs muss das verwendete EditorBrowsable Attribut auskommentiert werden.
  2. In der Datei CommandLineOptions.cs muss GetEntryAssembly durch GetCallingAssembly ersetzt werden.
  3. In der Datei DebugWriter muss Debug.Write durch Debug.WriteLine ersetzt werden.

Ergebnis: NUnitLiteSilver.dll.

Diese können wir im folgenden in einem Unit Test Projekt verwenden. Dazu erstellen wir ein neues Silverlight Class Library Projekt. Anschließend fügen wir diesem Projekt eine Referenz auf das NUnitLiteSilver Pojekt hinzu (oder eine Referenz auf NUnitLiteSilver.dll). Dann ergänzen wir noch ein paar Tests:

using NUnit.Framework;

namespace SomeTests
{
    [TestFixture]
    public class ExampleTestFixture
    {
        [Test]
        public void ThisTestIsOk() {
            Assert.That(5, Is.EqualTo(5));
        }

        [Test]
        public void ThisTestFails() {
            Assert.Fail("error!");
        }
    }
}

Was jetzt noch fehlt ist ein TestRunner. Silverlight bietet out of the box keine Konsolenanwendung, daher basteln wir uns einen ganz simplen Testrunner wie folgt: wir ergänzen ein weiteres Silverlight Projekt, diesmal vom Typ ‘Silverlight Project’, mit dem Namen NUnitLiteSilverRunner. Auch in dieses Projekt ergänzen wir eine Referenz auf NUnitLiteSilver.dll oder das zugehörige Projekt.

In der Datei Page.xaml ergänzen wir einen TextBlock in den wir die Ergebnisse des TestRunners schreiben:

<Canvas x:Name="parentCanvas"
        xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Loaded="Page_Loaded"
        x:Class="NUnitLiteSilverRunner.Page;assembly=ClientBin/NUnitLiteSilverRunner.dll"
        Width="640"
        Height="480"
        Background="White"
        >
  <TextBlock x:Name="results" Height="480" Width="640" />
</Canvas>

NUnitLite bringt einen TextUI TestRunner mit, der einen TextWriter als Parameter erwartet. Um in den TextBlock zu schreiben erstellen wir daher einen TextBlockTextWriter:

using System;
using System.IO;
using System.Windows.Controls;

namespace SilverlightTestRunner
{
    public class TextBlockWriter : TextWriter
    {
        private readonly TextBlock textBlox;

        public TextBlockWriter(TextBlock textBlox) {
            this.textBlox = textBlox;
        }

        public override void Write(char value) {
            textBlox.Text += value;
        }

        public override void Write(string value) {
            textBlox.Text += value;
        }

        public override void WriteLine(string value) {
            textBlox.Text += value + Environment.NewLine;
        }

        public override System.Text.Encoding Encoding {
            get { return System.Text.Encoding.Default; }
        }
    }
}

Anschließend ergänzen wir die Codebehind Datei Page.xaml.cs wie folgt:

using System;
using System.Windows.Controls;

using NUnitLite.Runner;
using SilverlightTestRunner;

namespace NUnitLiteSilverRunner
{
    public partial class Page : Canvas
    {
        public void Page_Loaded(object o, EventArgs e) {
            InitializeComponent();
            try {
                TextUI testRunner = new TextUI(new TextBlockWriter(results));
                testRunner.Execute(new string[] { "SomeTests, Version=1.0.0.0" });
            }
            catch (Exception e1) {
                results.Text += e1.Message;
            }
        }
    }
}

Nun können wir das Projekt NUnitLiteSilverRunner als Startprojekt festlegen und mit F5 die Ausführung beginnen. Ergebnis: System.Reflection.Assembly.GetName() schmeißt eine Exception.

NUnitLiteSilver-3

Ich habe kurzerhand überall den Aufruf Assembly.GetName() durch Assembly.Fullname ersetzt. In der Methode TextUI.WriteCopyright() habe ich die Zeilen die die Version der Assembly ermitteln und ausgeben auskommentiert. Was man tun muss damit Assembly.GetName() unter Silverlight ausgeführt wird bleibt noch zu klären.

Ergebnis? Trommelwirbel…… Die Tests werden ausgeführt :-)

NUnitLiteSilver-4