Neues rund um's Thema .Net, Team Foundation Server und SCRUM RSS 2.0
# Tuesday, January 31, 2012

Der TFS bzw. der MTM unterstützen leider keine Versionierung von Test Cases. Wenn man nun für unterschiedliche Versionen einer Software Test Cases verwalten möchte, muss man die Test Cases kopieren. Wie damit die Versionierung von Test Cases abgebildet werden kann, habe ich hier beschrieben.

Um das Kopieren größerer Mengen von Test Cases zu vereinfachen, gibt es nun das Test Case Copy Tool von Anna Russo.

http://www.improvingsoftwarequality.com/2012/01/new-version-of-bulk-copy-test-cases.html

Tuesday, January 31, 2012 10:17:17 AM (Mitteleuropäische Zeit, UTC+01:00)  #    Comments [0] -
Testing | TFS 2010 | Tools | VS 2010
# Wednesday, November 09, 2011

Eine häufige Frage ist, wie ich mit dem TFS und Microsoft Test Manager (MTM) die Versionierung von Test Cases bewerkstellige. Ziel dabei ist, dass ich verschiedene Releases meiner Software mit den dazu passenden Test Cases testen möchte, also z.B. für die aktuelle Entwicklung nutze ich einen neueren Test Cases da sich die Funktion inzwischen verändert hat aber wenn ich einen Hotfix für eine frühere Version testen möchte, benötige ich dafür natürlich den passenden Test Cases zu diesem Release.

Die aktuelle Lösung sieht im MTM so aus, dass man einen Test-Plan je Version einrichtet. In diesem Test-Plan habe ich dann die Test-Cases für die aktuelle Version referenziert. Für die nächste Version legt man einen neuen Test-Plan an und kopiert die Test-Suites.

image

Durch dieses Kopieren wird ein neuer Test-Plan angelegt der dann allerdings auf die selben Test Cases verweist wie die der Plan für die erste Version. Das ist ja genau die Ausgangssituation die man in den meisten Fällen haben möchte denn die meisten Test Cases sind ja in der neuen Version gleich wie in der Vorgänger-Version und diese werden ggf. durch neue Test Cases (z.B. 4a) ergänzt. Wenn sich ein Test Case nun ändert, dann darf dieser im neuen Test-Plan nicht angepasst werden, sonst würde ja damit auch der Test-Plan der Vorgängerversion geändert werden. Statt dessen muss der Test Case kopiert und die Kopie (2b) dem neuen Test Plan zugeordnet werden. Die Kopie kann nun geändert werden.

image

Wer eine größere Menge von Test Cases kopieren muss kann dafür übrigens auch ein Tool verwenden das Anna Russo veröffentlicht hat:

http://improvingsoftwarequality.blogspot.com/2011/11/bulk-copy-test-cases-tool-for-microsoft.html

Wednesday, November 09, 2011 2:23:52 PM (Mitteleuropäische Zeit, UTC+01:00)  #    Comments [0] -
Team System Server | Testing | TFS 2010 | VS 2010
# Wednesday, October 19, 2011

Beim Deployment einer neuen Environment kommt folgende Fehlermeldung:

image

TF259115: Team Foundation Server could not find any suitable host to deploy the virtual machine: HPC Template.
Contact your administrator to fix the issues on the hosts below. (Hosts are listed in brackets)
1. Memory requirement of the virtual machine(s) exceeds the available host resources. The placement policy for this host group is set to be conservative and hence virtual machines that are in stopped state are also accounted as consuming host resources. Your administrator can change this policy by running the TfsLabConfig tool. (SarHyperV04)

Der Grund für die Meldung liegt darin, dass das Lab Management zunächst davon ausgeht, dass auf dem Hyper-V Host ausreichend Ressourcen (RAM) verfügbar sein müssen um alle Environments gleichzeitig zu starten um hier auf Nummer sicher zu gehen. Das ist allerdings für die Praxis eher ungeeignet. Hier möchte man auf einem Host mehrere, teilweise sogar viele Environments anlegen von denen dann aber immer nur einzelne laufen.

Glücklicherweise kann man das Verhalten aber konfigurieren. Dazu geht man einfach auf den TFS App-Tier und gibt dort folgenden Befehl ein:

tfsconfig lab /settings /CollectionName:<Collection> /hostGroup /edit /name:<Host Group Name> /labenvironmentplacementpolicy:aggressive

Dabei ist zu beachten, dass für den CollectionName auch wirklich nur der Name und nicht wie an anderen Stellen üblich die URI angegeben wird.

Weitere Infos finden sich hier: http://msdn.microsoft.com/en-us/library/dd547199(VS.100).aspx

Wednesday, October 19, 2011 3:58:03 PM (Mitteleuropäische Sommerzeit, UTC+02:00)  #    Comments [0] -
Lab Management | Team System Server | Testing | VS 2010
# Friday, August 26, 2011

Das Lab Management des Team Foundation Servers eignet sich besonders gut um darin Coded UI Tests automatisiert im Rahmen eines Builds auszuführen. Der Build setzt die VM dabei auf einen Snapshot zurück, deployed die Applikation dann in die VM und führt dann die CUIT aus. Wie das Ganze funktioniert habe ich in einem Webcast beschrieben (http://www.microsoft.com/germany/msdn/webcasts/library.aspx?id=1032476976).

Dabei kann allerdings nun ein Problem auftreten. Der Test meldet bei der Ausführung:

“Automation engine is unable to playback the test because it is not able to interact with the desktop.  This could happen if the computer running the test is locked or it’s remote session window is minimized.”

Das Problem besteht darin, dass der CUIT eine interaktive Desktop Session benötigt um darin ausgeführt werden zu können. Als ich mich mit dem Environment Viewer auf die Environment verbunden habe, konnte ich feststellen, dass die VM beim Anmeldebildschirm stand. Das hatte ich nicht erwartet das die VM mit einem Autologon versehen war und ich den Snapshot auch im angemeldeten Zustand erstellt habe. ich hätte also erwartet, dass die VM nach einem Restore des Snapshots auch wieder angemeldet ist und der Test problemlos laufen kann.

Um die Ursache des Problems zu erläutern müssen wir etwas tiefer einsteigen. Der Environmen Viewer hat 2 Betriebs-Modi. Einmal Host-based und einmal Guest-based. Der aktuelle Modus wird rechts unten im Environment Viewr angezeigt

image

Host-based ist dabei die Verbindungsart bei der der Environment Viewer über den Hyper-V Host auf die VM zugreift. Dieser Modus erlaubt es auch mit der VM zu interagieren wenn diese noch gar nicht komplett hochgefahren ist, z.B. um aus dem Boot-Menü einen Eintrag zu wählen.

Guest-based ist eine normale RDP (Remote Desktop Protocol) Verbindung. Dafür muss die VM bereits hochgefahren sein. Guest-based Verbindungen sind etwas performanter und erlauben auch zusätzliche Features wie z.B. den Austausch von daten über die Zwischenablage.

Host-based wird dann verwendet wenn:

1.) Der client der den Environment Viewer ausführt als Betriebssystem mindestens Windows XP SP3, Windows Visua SP1, Windows 7 oder Windows Server 2008 ausführt und
2.) Der Benutzer der den Environment Viewer ausführt auch der Ownder der Environment ist

image

Weitere Informationen zu den verschiedenen Connection Types finden sich unter http://msdn.microsoft.com/en-us/library/ee518907.aspx.

Zurück zu dem obenen beschriebenen Problem. Der Build funktioniert nur dann, wenn der Snapshot auf den der Build zurücksetzt im Host-based Modus erstellt wurde. Andernfalls bekommt man auch in der Build Definition bei der Auswahl des Snapshots einen entsprechenden Hinweis.

image

Zu beachten ist allerdings, dass dieser Hinweis nur an dieser Stelle kommt, d.h. wenn man den Wizard des Lab BuildProcessTemplates anzeigt oder bei der Ausführung bekommt man keinen Hinweis mehr. Problem bei mir war, dass ich den Snapshot initial im Host-based Modus erstellt hatte und damit den Build angelegt habe. Anschließend habe ich den Snapshot aber gelöscht und neu angelegt und nun war ich im Guest-based Modus.

Problem-Lösung:

Wie lösen wir nun also dieses Problem? Es gibt zwei Möglichkeiten:

1.) Wir erstellen die Snapshots immer im Host-based Modus. Dazu müssen wir im Environment Viewer mit dem Benutzer angemeldet sein der auch der Owner der Environment ist. Wie man den Owner einer Environment ändert ist hier beschrieben: http://blogs.msdn.com/b/lab_management/archive/2010/11/08/enabling-host-based-connection-for-virtual-environments.aspx

2.) Wir verwenden einen Snapshot der im nicht gebooteten Zustand der VM erstellt wird. Der Build startet die VM dann automatisch und die VM nutzt einen Autologon um sich anzumelden. Damit kann der CUIT nun auch ausgeführt werden.

Friday, August 26, 2011 12:28:13 PM (Mitteleuropäische Sommerzeit, UTC+02:00)  #    Comments [0] -
Lab Management | Team System Server | Testing | TFS 2010 | VS 2010
# Sunday, November 21, 2010

Mit dem Team Foundation Build ist es einfach, Tests im Rahmen von automatisierten Builds auszuführen. Standardmäßig werden die Tests jedoch auf dem Buildrechner selbst ausgeführt. Das ist in verschiedenen Szenarien jedoch nicht erwünscht, sondern man möchte die Tests in einer Referenzumgebung ausführen die der Zielumgebung, in der die Anwendung ausgeführt werden soll, möglichst nahe kommt. Vor allem für GUI-Tests ist dieses Szenario wichtig.

image

Mit Visual Studio 2010 gibt es dafür LabManagement um virtualisierte Testumgebungen bereitzustellen und über ein vorbereitetes Build Template Tests darin auszuführen. Jedoch lässt sich diese Funktion auch ohne LabManagement erreichen, z.B. wenn ein anderes Virtualisierungssystem als Hyper-V oder rein physikalische Testumgebungen eingesetzt werden sollen. Im Folgenden soll beschrieben werden, wie dieses Szenario einzurichten ist.

Hierzu muss zunächst ein Testcontroller eingerichtet werden. Dieser kann beispielsweise auf dem TFS Server installiert werden. Auf der Testmaschine muss anschließend ein Testagent installiert und auf den Testcontroller registriert werden. Weitere Hinweise zur Installation und Konfiguration von Testcontrollern und –agents finden sie unter http://msdn.microsoft.com/de-de/library/dd648127.aspx. Es sollte beachtet werden, dass der Test Agent als interaktiver Prozess konfiguriert sein muss, wenn UI-Tests auf der Testmaschine ausgeführt werden sollen. Und der Testagent muss auf dem Testcontroller registriert  sein.

image

image

Der Testcontroller darf nicht für ein Teamprojekt registriert sein.

image

Anschließend können wir einen Build für das gewünschte Projekt einrichten. Der Build soll in unserem Szenario auf einem separaten Buildcomputer ausgeführt werden. Um das Deployment des Buildergebnisses auf die Testmaschine zu bewerkstelligen, passen wir das Buildtemplate ein wenig an. Dazu legen wir zunächst 2 neue Arguments an. Anschließend Platzieren wir unterhalb der „If BuildSettings.HasProjectToBuild“ Activity eine If-Condition auf der wir auf das Argument DeployForTest prüfen. Im Then-Zweig fügen wir dann eine CopyDirectory-Activity ein für die wir als Source die Droplocation und als Destination das Argument DeployForTestTarget einstellen. Damit wird unser Buildergebnis in dan Verzeichnis kopiert das wir in unserer Build Definition einstellen können.

2010-11-22_2207

Das BuildTemplate können wir nun unter einem neuen Namen speichern und einchecken. Auf dieser Basis erstellen wir nun mal einen ersten Build. In den Process Einstellungen definieren wir nun, dass das Deployment auf die Testmaschine ausgeführt werden soll und wir geben den UNC-Pfad an wohin die Dateien deployed werden sollen.

image

Nach dem Ausführen des Builds können wir prüfen, ob die Dateien korrekt auf die Testmaschine deployed wurden. Die Tests die wir in unserem Projekt haben werden allerdings immer noch auf unserer Buildmaschine ausgeführt. Um das zu ändern, müssen wir die Testsettings anpassen. Unter Test / Edit Test Settings  wählen wir zunächst Local aus um diese Einstellung anzupassen.

image

Hier müssen wir Remote Execution einstelle und den entsprechenden Build Controller auswählen. Diese Einstellungen können wir dann unter einem neuen Namen abspeichern und einchecken.

Anschließend wählen wir diese Test Settings in unserem Build aus.

image
image

Damit werden unsere Tests die wir in der Solution definiert haben nun auf unserer Testmaschine ausgeführt. Dies können sowohl Unit-Tests als auch Coded UI Tests sein. Als erweitertes Szenario können z.B. im Rahmen des Build Setups erstellt werden die dann über die CopyDirectory Activity auf die Testmaschine kopiert werden. Dann kann mit Hilfe eines Coded UI Tests das Setup ausgeführt und anschließend die Funktionen der Anwendung getestet werden.

Ein wichtiger Punkt ist noch, dass wir aktuell nicht kontrollieren können, auf welchem Testcomputer die Tests ausgeführt werden, wenn wir auf dem Testcontroller mehrere Agents registriert haben. Das wollen wir nun noch ändern. Dazu wählen wir unter Test / Manage Test Controllers unseren Testcontroller und den entsprechenden Agent aus.

image

Über Properties können wir dem Agent nun Attribute zuordnen, z.B. ein MachineName.

image

Nun können wir in unseren Testsettings einstellen auf welchem Agent unsere Tests ausgeführt werden sollen. Dazu fügen wir erst eine Rolle hinzu und wählen aus, dass auf dieser Rolle Tests ausgeführt werden können. Nun Geben wir das zuvor definierte Attribut mit dem selben Wert an.

image

Nun können wir eindeutig steuern, wo die Ausführung der Tests erfolgen soll und wir können beispielsweise mehrere Testcomputer mit verschiedenen Betriebssystemen zur Ausführung der Tests nutzen.

Sunday, November 21, 2010 11:32:09 PM (Mitteleuropäische Zeit, UTC+01:00)  #    Comments [0] -
Team System Server | Testing | TFS 2010 | VS 2010
# Tuesday, October 12, 2010

Beim starten einer Environment im Microsoft Lab Management dauert es meist geraume Zeit, bis die Workflow capabilities bereit zur Ausführung sind.

image

Will man diese Zeit reduzieren, ist ein einfaches Mittel in den VMs das IPv6 Protokoll auf den Netzwerkkarten zu reduzieren. Bei mir hat das die Wartezeit für die Workflow capabilities von 2:44 Min auf 0:40 Min reduziert.

Tuesday, October 12, 2010 9:45:40 PM (Mitteleuropäische Sommerzeit, UTC+02:00)  #    Comments [0] -
Team System Server | Testing | TFS 2010 | VS 2010
# Friday, October 01, 2010

Um mit dem MS Test Framework eine Code Coverage Analyse auszuführen, muss diese zunächst aktiviert werden. Da es hierbei immer wieder zu Fragen / Problemen kommt, möchte ich den Weg hier einmal ausführlich beschreiben:

Zunächst öffnet man eine vorhandene Test Settings Datei

image

Hier aktiviert man zunächst unter “Data and Diagnostics”´die Code Coverage und öffnet dann die Konfiguration für diesen Data Collector.

image

Hier wählt man nun die Assemblies für die die Coverage Analyse erstellt werden soll

image

Anschließend speichert man die Test Settings unter einem eigenen Namen wie beispielsweise “CodeCoverage” ab. Dies kann man als aktive Test Settings selektieren.

image

Nun kann man Unit-Tests ausführen und anschließend im Test Results Fenster die Code Coverage Results aufrufen.

image

Die Ergebnisse werden nun tabellarisch angezeigt.

image

Zusätzlich kann man dann noch die Coverage im Code anzeigen lassen. Hierzu einfach in der Toolbar den gekennzeichneten Butten klicken.

image

Hier sieht man nun, welche Codebereiche noch nicht durch die Tests abgedeckt sind. Hier sollten also noch ein paar weiter Tests geschrieben werden um die Testabdeckung zu erhöhen. Welche Input-Parameter diese abdecken sollten, zeigt die Coverage Analyse.

Tipp: Sollte die Coverage Anlayse auf dem oben beschriebenen Weg nicht gleich angezeeigt werden, hilft manchmal ein neustart von Visual Studio. Ich hatte schon verschiedendlich Situationen, als die Einstellung nicht sofort übernommen wurde.

Friday, October 01, 2010 11:42:43 PM (Mitteleuropäische Sommerzeit, UTC+02:00)  #    Comments [0] -
Testing | VS 2010
# Wednesday, September 15, 2010

Web Performance Tests zeichnen die HTTP-Kommunikation zwischen einem Client und einem Webserver auf und können diesen dann wieder abspielen. Somit lässt sich der Server-Code relativ einfach “von Außen” testen und diese Tests eignen sich auch sehr gut um Load-Tests zu generieren.

Manche Web-Anwendungen verwenden die URL um die Session ID zu übermitteln, vor allem wenn keine Cookies zur Verfügung stehen. Dann entsteht allerdings das Problem, dass die aufgezeichneten Requests nicht wieder sauber abgespielt wreden können, da diese dann ja auf eine nicht mehr aktive Session verweisen. Dieses Problem kann man allerdings recht elegant lösen:

Zunächst verwendet man einen Request der ohne Session ID arbeitet um die Applikation zu starten. Dieser liefert normalerweise im Response einen Redirect auf die URL inkl. SessionID zurück.

image

Diesem Request kann nun in der Definition des Web Tests eine Extraction Rule hinzugefügt werden (Rechte Maustaste / Add Extraction Rule). Hier kann mit der Extract Text Rule nun im Response nach einem Text gesucht werden. Dazu wird eine Startsquenz “(S(" und eine Endesequenz “))” angegeben. Der Text dazwischen wird dann extrahiert und in den Parameter “URLSessionID” geschrieben.

image

image

Mit einem Find and Replace auf dem wurzelknoten des Tests  können nun alle URLs im Test automatisch aktualisiert werden.
image

Hier wird einfach die aufgezeichnete Session ID durch den Parameter “{{URLSessionID}}” ersetzt.

image

Der so modifizierte Test kann nun reproduzierbar ausgeführt werden.

Wednesday, September 15, 2010 6:44:54 PM (Mitteleuropäische Sommerzeit, UTC+02:00)  #    Comments [0] -
Testing | VS 2010
# Thursday, April 02, 2009

Der Tatsache, dass Testen eine wichtige Bedeutung in der Software-Entwicklung hat, trägt Microsoft ja bereits seit einiger Zeit Rechnung indem eine spezielle Edition des Visual Studio für Tester generiert wurde. Diese Edition besitzt umfangreiche Funktionenzu verschiedenen Test-Methoden. Das Ranger-Team hat nun einen Quick Reference Guide veröffentlicht der auf 83 Seiten diese Funktionen beschreibt und verschiedene Best Practices anbietet. Hierbei sind die Erfahrungen eingeflossen, die Service Labs, ein großes Test-Center, bei der Adaption von Team Test gemacht hat. Das Dokument enthält viele wertvolle Hinweise, wie VSTT in der Praxis eingesetzt und individuell erweitert werden kann.

Definitiv lesenswert für jeden, der etwas mehr über dieses Toolset erfahren möchte.

Download VSTT 2008 Quick Reference Guide

Thursday, April 02, 2009 8:33:23 AM (Mitteleuropäische Sommerzeit, UTC+02:00)  #    Comments [0] -
Team System Server | Testing
# Wednesday, April 01, 2009

Das Thema Test Driven Development oder auch Test First Developent gewinnt immer mehr an Beachtung. Keine Konferenz, keine Zeitschrift, kein Sprecher der was auf sich hält kommt um das Thema herum. Doch nach dem überzeugenden Vortrag sitzt man zu Hause im Büro vor einem leeren Project und wie nun anfangen? Hier scheitern bereits die ersten, weil entsprechende Publikationen oft zwar die Vorteile ausführlich schildern, aber nicht den Einstieg darstellen. Deshalb möchte ich hier einen entsprechenden Einstieg geben und mit einem wirklich leeren Projekt beginnen.

Die Theorie um TDD will ich hier einfach weglassen. Hierzu gibt es bereits Informationen genug. Und wir werden verschiedene Vereinfachung vornehmen, über die Profis etwas die Nase rümpfen werden, aber damit erhalten wir ein einfaches und praktikable Einstiegsszenario.

Zum Einsatz kommen hierbei die Testfunktionen von Visual Studio 2008 die ab der Professional Edition enthalten sind. Wir beginnen mit einer komplett leeren Solution.

image

Die Frage, die nun im Raum steht, ist: Wie schreibe ich einen Test ohne eine Methode zu haben. Ein Unit-Test besteht ja im Prinzip darin, dass wir eine Methode aufrufen und den Rückgabewert mit einem Erwartungswert vergleichen. Der Test wird aber nicht einmal kompilieren, solange die Methode nicht definiert ist. Der Workaround an dieser Stelle sieht dann oft so aus, dass man von der Methode und ihrer Klasse erst einmal einen Stub anlegt der im wesentlichen eine “ThrowNotImplemented”-Exception wirft. Damit haben wir aber eigentlich schon mehr implementiert als nach dem TDD uns lieb ist.

Ein etwas eleganterer Ansatz geht über die Definition von Interfaces. Diese Vorgehensweise eignet sich besonders gut bei einer komponentenorientierten Architektur mit einem Contract First Ansatz. Dabei werden die Schnittstellen der einzelnen Komponenten erst über Contracts (Interfaces) beschrieben bevor diese implementiert werden. Den TDD-Ablauf Rot > Grün > Refactor erweitern wir ein wenig. Damit ergibt sich folgende Abfolge:

Contract definieren > Test implementieren > Rot > Funktion implementieren > Grün > Refactor

D.h. wir erstellen in einem ersten Schritt einen Contract (genau genommen machen wir damit kein TDD sondern ein Test First. Beim TDD ist der Test das erste was erstellt werden muss, aber das ist in meinen Augen eher Haarspalterei, so funktioniert es einfach in der Praxis). Wir erstellen ein neues ClassLibrary-Projekt und erstellen dort ein Interface.

   1: namespace Contracts
   2: {
   3:     public interface IOrderCalculator
   4:     {
   5:         decimal CalculateShippinghCosts(decimal sum, decimal freeShippingMin, decimal shippingCosts);
   6:     }
   7: }

Wir wollen hier ein überschaubares, aber auch nicht zu triviales Beispiel verwenden. Die Methode CalculateShippingCosts soll zu einem gegebenen Rechnungsbetrag Versandkosten hinzuaddieren, wenn ein bestimmter Mindestbetrag nicht erreicht ist. So damit haben wir den Contract erstellt. Nun wollen wir einen Test dazu erstellen. Das geht am schnellsten durch einen Rechts-Klick auf die Methode und dann “Create Unit-Tests”.

image

Hier wird standardmäßig ein neues Test-Projekt angelegt. Darin wird ein entsprechender Unit-Test generiert.

   1: [TestMethod()]
   2: public void CalculateShippinghCostsTest()
   3: {
   4:     IOrderCalculator target = CreateIOrderCalculator(); // TODO: Initialize to an appropriate value
   5:     Decimal sum = new Decimal(); // TODO: Initialize to an appropriate value
   6:     Decimal freeShippingMin = new Decimal(); // TODO: Initialize to an appropriate value
   7:     Decimal shippingCosts = new Decimal(); // TODO: Initialize to an appropriate value
   8:     Decimal expected = new Decimal(); // TODO: Initialize to an appropriate value
   9:     Decimal actual;
  10:     actual = target.CalculateShippinghCosts(sum, freeShippingMin, shippingCosts);
  11:     Assert.AreEqual(expected, actual);
  12:     Assert.Inconclusive("Verify the correctness of this test method.");
  13: }

Damit können wir den Test bereits zum ersten mal ausführen und er geht wie erwartet auf Rot. Aber Moment, wie funktioniert das. Wie kann der Test eine Methode auf einem Interface aufrufen? Es gibt ja noch keine Implementierung des Interfaces und ein Interface selbst lässt sich ja nicht instanziieren. Hier baut Visual Studio einen kleinen Workaround. In Zeile 4 im obigen Code sieht man, dass eine Instanz des target-Objektes über die Methode CreateIOrderCalculator() erstellt wird. Diese Methode wollen wir mal etwas genauer anschauen.

   1: internal virtual IOrderCalculator CreateIOrderCalculator()
   2: {
   3:     // TODO: Instantiate an appropriate concrete class.
   4:     IOrderCalculator target = null;
   5:     return target;
   6: }

Hier wird das Objekt einfach mit null initialisiert. Ein einfacher, aber wirkungsvoller Workaround. Damit erreichen wir unser Ziel, dass der Test kompiliert aber fehlschlägt. Nach der Implementierung ersetzen wir das null einfach durch die entsprechende Initialisierung. Damit können wir nun unsere Testcases Implementieren.

   1: [TestMethod()]
   2: public void CalculateShippinghCosts_Sum_Below_FreeShippingMin()
   3: {
   4:     IOrderCalculator target = CreateIOrderCalculator();
   5:     Decimal sum = 1;
   6:     Decimal freeShippingMin = 10;
   7:     Decimal shippingCosts = 5;
   8:     // We are below min, so we have to add shippingCosts
   9:     Decimal expected = 6;
  10:     Decimal actual;
  11:     actual = target.CalculateShippinghCosts(sum, freeShippingMin, shippingCosts);
  12:     Assert.AreEqual(expected, actual);
  13: }
  14:  
  15: [TestMethod()]
  16: public void CalculateShippinghCosts_Sum_Above_FreeShippingMin()
  17: {
  18:     IOrderCalculator target = CreateIOrderCalculator();
  19:     Decimal sum = 20;
  20:     Decimal freeShippingMin = 10;
  21:     Decimal shippingCosts = 5;
  22:     // We are above min, so we don't add shippingCosts
  23:     Decimal expected = 20;
  24:     Decimal actual;
  25:     actual = target.CalculateShippinghCosts(sum, freeShippingMin, shippingCosts);
  26:     Assert.AreEqual(expected, actual);
  27: }
  28:  
  29: [TestMethod()]
  30: public void CalculateShippinghCosts_Sum_Equal_FreeShippingMin()
  31: {
  32:     IOrderCalculator target = CreateIOrderCalculator();
  33:     Decimal sum = 10;
  34:     Decimal freeShippingMin = 10;
  35:     Decimal shippingCosts = 5;
  36:     // We are equal min, so we don't add shippingCosts
  37:     Decimal expected = 10;
  38:     Decimal actual;
  39:     actual = target.CalculateShippinghCosts(sum, freeShippingMin, shippingCosts);
  40:     Assert.AreEqual(expected, actual);
  41: }

Damit haben wir unser Szenario ausreichend beschrieben. Wir können nun an die Implementierung gehen.Dazu legen wir ein neues Projekt an in dem wir eine Klasse definieren die wir von unserem Interface ableiten.

   1: namespace Components
   2: {
   3:     public class cOrderCalculator : IOrderCalculator
   4:     {
   5:         public decimal CalculateShippinghCosts(decimal sum, decimal freeShippingMin, decimal shippingCosts)
   6:         {
   7:             // If sum is greater than Min then don't add shipping costs
   8:             if (sum > freeShippingMin)
   9:                 return sum;
  10:             else
  11:                 // else add shipping costs
  12:                 return sum + shippingCosts;
  13:         }
  14:     }
  15: }

Nun müssen wir unbedingt noch daran denken, die Initialisierung des Testobjektes in unserer Testmethode anzupassen.

   1: internal virtual IOrderCalculator CreateIOrderCalculator()
   2: {
   3:     IOrderCalculator target = new cOrderCalculator();
   4:     return target;
   5: }

Nun können wir die Tests ausführen.

image

Oh, ein Test schlägt fehl. Bei genauerer Betrachtung stellen wir fest, dass wir bei der Implementierung den Fall dass die Summe gleich der Grenze ist nicht richtig berücksichtigt haben. Also hat sich hier der TDD-Ansatz schon bewährt und wir können den Fehler beheben. Damit sind alle Tests grün und wir können weiter fortfahren. Wir könnten nun z.B. auf unserem Interface weitere Methoden definieren und dafür Tests anlegen.

Also eigentlich gar nicht so schwer das mit dem TDD, oder? Freue mich auf euer Feedback.

Die Solution gibt es zum Download.

Happy Testing!

Wednesday, April 01, 2009 2:10:53 AM (Mitteleuropäische Sommerzeit, UTC+02:00)  #    Comments [2] -
Eigene Tutorials | Qualitätsmanagement | Testing | Tipps und Tricks
# Tuesday, February 24, 2009

MSDN Webcasts 

Zusammen mit Christian Binder habe ich einen WebCast aufgenommen in dem wir PEX vorstellen. Der WebCast wird ab 12.03 online sein.

Details zur Veranstaltung: Unit-Test Generierung mit PEX [1032405246] - Microsoft Deutschland GmbH

Tuesday, February 24, 2009 9:06:26 PM (Mitteleuropäische Zeit, UTC+01:00)  #    Comments [0] -
PEX | Testing
# Friday, February 20, 2009

MSDN Webcasts

Zusammen mit Christian habe ich einen Webcast zum Thema Testing Practices aufgenommen. In dem Webcast werden zunächst verschiedene Testmethoden vorestellt und anschließend werden verschiedene Aspekte einer Teststrategie diskutiert wie z.B. Methoden zur Testfall-Ermittlung.

Der komplette Abstract lautet:

Qualität spielt in Software-Projekten eine immer größere Rolle. Ein wesentlicher Aspekt für Software-Qualität ist das Testen. Der Webcast stellt zunächst kurz die verfügbaren Testmethoden in Visual Studio vor und zeigt anschließend Aspekte einer Test-Strategie auf. Darüber hinaus wird die Integration mit dem Team Foundation Server kurz beleuchtet und es werden Methoden zur Testfallermittlung beschrieben.

Über ein Feedback zum Webcast würde ich mich freuen.

http://www.microsoft.com/germany/msdn/webcasts/library.aspx?id=1032405240

Friday, February 20, 2009 7:12:30 AM (Mitteleuropäische Zeit, UTC+01:00)  #    Comments [0] -
PEX | Qualitätsmanagement | Testing | Vorträge

An einem kleinen Beispiel möchte ich kurz erläutern, wie PEX parametrisierte Unit-Tests nutzt und wie man diese nutzen kann um bestimmte Test-Szenarien abzubilden. Wir nehmen einen kleinen Codeausschnitt um uns das mal anzusehen:

   1: public class TotalSum
   2: {
   3:     private double total = 0;
   4:  
   5:     public double CalculateTotals(List<cOrderPosition> OrderPositions, double Rebate)
   6:     {
   7:         if (OrderPositions == null)
   8:             return 0;
   9:  
  10:         foreach (cOrderPosition orderPos in OrderPositions)
  11:         {
  12:             if (orderPos.Amount > 0 && orderPos.SinglePrice > 0)
  13:                 total += orderPos.Amount * orderPos.SinglePrice;                
  14:         }
  15:  
  16:         if (Rebate > 0)
  17:             total = total * (1 - Rebate);
  18:  
  19:         return total;
  20:     }
  21:  
  22:     public class cOrderPosition
  23:     {
  24:         public int ProductID { get; set; }
  25:         public double Amount { get; set; }
  26:         public double SinglePrice { get; set; }
  27:     }
  28: }

 

Auf den ersten Blick scheint da alles OK zu sein. Mal sehen was PEX daraus jetzt macht.

image

Zunächst sehen wir, dass PEX 3 Probleme mit Object Creations hat. Für den ersten Fall lassen wir PEX einfach automatisiert eine Factory erstellen indem wir auf "Accept/Edit factory" klicken. Für die Liste müssen wir ebenfalls eine Factory erstellen. Diese Factory wollen wir jetzt noch anpassen:

   1: [PexFactoryMethod(typeof(List<TotalSum.cOrderPosition>))]
   2: public static List<TotalSum.cOrderPosition> Create(int NumberOfItems)
   3: {
   4:     List<TotalSum.cOrderPosition> list = new List<TotalSum.cOrderPosition>(NumberOfItems);
   5:     if (NumberOfItems > 10)
   6:         NumberOfItems = 10;
   7:  
   8:     for (int i = 0; i < NumberOfItems; i++)
   9:     {
  10:         list.Add(new TotalSum.cOrderPosition()
  11:         {
  12:             ProductID = i + 1,
  13:             SinglePrice = new Random().NextDouble() * 10,
  14:             Amount = new Random().NextDouble() * 10
  15:         });
  16:     }
  17:        
  18:     return list;
  19: }

 

Abhängig von der Anzahl Items die als Parameter übergeben wird, wird die Liste mit entsprechend vielen Elementen befüllt. Nun erhalten wir Ergebnisse bei der Exploration.

image

Und es sind alle grün. Also alles OK? Jetzt kommt der parametrisierte Unit-Test in's Spiel. Dazu müssen wir erst mal die Test generieren. Dazu einfach alle Einträge markieren und rechts auf "Save..." klicken.

image 

   1: [TestMethod]
   2: [PexGeneratedBy(typeof(TotalSumTest))]
   3: public void CalculateTotals04()
   4: {
   5:     TotalSum totalSum;
   6:     List<TotalSum.cOrderPosition> list;
   7:     double d;
   8:     totalSum = TotalSumFactory.Create();
   9:     list = ListFactory.Create(1);
  10:     d = this.CalculateTotals(totalSum, list, 0);
  11:     Assert.AreEqual<double>(42.232177096754121, d);
  12: }

Wenn wir uns eine der generierten Testmethoden mal genauer anschauen, dann erkennen wir dass in Zeile 9 unsere ListFactory aufgerufen wird und in Zeile 10 wird eine Methode CalculateTotals aufgerufen. Bei dieser Methode handelt es sich um unseren parameterisierten Unit-Test der in der .cs-Datei abgelegt ist. Dieser parametrisierte Unit-Test nimmt Input-Werte engegen und ruft damit die eigentliche Funktion auf. Man kann den parametrisierten Unit-Test eigentlich mit einem datengetriebenen Test vergleichen, mit dem Unterschied dass die Daten nicht aus einer Datenquelle kommen sondern von den jeweiligen Testmethoden übergeben werden.

Wir können den parametrisierten Unit-Test selbst anpassen und auch Asserst einfügen. Was wir nun hier tun wollen, ist die eigentliche Test-Methode zwei mal aufzurufen und zu prüfen, ob beide Ergebnisse übereinstimmen. Bei gleichen Eingangswerten sollte dies ja der Fall sein. Der parametrisierte Unit-test sieht dann ungefähr so aus.

   1: [TestClass]
   2: [PexClass(typeof(TotalSum))]
   3: [PexAllowedExceptionFromTypeUnderTest(typeof(ArgumentException), AcceptExceptionSubtypes = true)]
   4: [PexAllowedExceptionFromTypeUnderTest(typeof(InvalidOperationException))]
   5: public partial class TotalSumTest
   6: {
   7:     [PexMethod]
   8:     public double CalculateTotals(
   9:         [PexAssumeUnderTest]TotalSum target,
  10:         List<TotalSum.cOrderPosition> OrderPositions,
  11:         double Rebate
  12:     )
  13:     {
  14:         double result = target.CalculateTotals(OrderPositions, Rebate);
  15:         double result2 = target.CalculateTotals(OrderPositions, Rebate);
  16:         Assert.AreEqual(result, result2);
  17:         return result;
  18:     }
  19: }

 

Diese Prüfung wird nun für alle Testmethoden ausgeführt. Und wie sieht das Ergebnis aus?

image

Wir erhalten nun einen Fehlerfall. Wenn man sich den Code der Test-Methode nochmals genauer anschaut, stellt man fest, dass die lokale Variable total beim erneuten Aufruf nicht zurückgesetzt wird - ein klassischer Fehler. Wenn wir die Variable in der Methode zurücksetzen, dann werden unsere Testfälle auch alle erfolgreich sein.

Somit haben wir mit Hilfe von PEX einen gängigen Fehler gefunden der in Real-World-Projekten sicher im Code selbst nicht so offensichtlich wäre.

Friday, February 20, 2009 1:20:23 AM (Mitteleuropäische Zeit, UTC+01:00)  #    Comments [1] -
PEX | Qualitätsmanagement | Testing
# Thursday, February 19, 2009

Ich habe in einem früheren Post bereits einige Beispiele für den Einsatz von PEX beschrieben. ich möchte nun in loser Reihe weitere Erkenntnisse die ich beim Experimentieren mit PEX gewinne hier veröffentlichen. Heute möchte ich mich mit Overflow-Exceptions beschäftigen. Anlass war eine Diskussion mit Nico. Als erstes Beispiel wollen wir uns mal folgenden Code ansehen:

   1: public decimal Calc(decimal Value, bool Increase)
   2: {
   3:     if (Increase)
   4:         return Value+1;
   5:     else
   6:         return Value-1;
   7: }

Für eine komplette Codeabdeckung muss PEX eigentlich nur den Boolean-Parameter Increase berücksichtigen. Der Parameter Value kann eigentlich beliebig gewählt werden, auf die Code-Abdeckung hat der keinen Einfluss. Aber natürlich erkennt man dass es natürlich auch Fälle gibt in denen die Methode eine OverflowException wirft, nämlich bei value = decimal.MaxValue, Increase = true und value = decimal.MinValue, Increase = false.

Das erfreuliche ist, dass mit der aktuellen Version (0.9.40105.0) PEX zusätzlich zur Codeabdeckung auch Grenzwerte berücksichtigt:

image

Bei einem anderen Beispiel funktioniert das leider (noch) nicht.

   1: public decimal ToDecimal(double Value)
   2: {
   3:     return (decimal)Value;
   4: }

Hier wird leider keine Grenzwertbetrachtung gemacht, die ja zu einer Exception führen würde da der Wertebereich von decimal kleiner ist als der von double.

image

Thursday, February 19, 2009 8:54:48 PM (Mitteleuropäische Zeit, UTC+01:00)  #    Comments [0] -
PEX | Testing
# Wednesday, February 18, 2009

Bei Unit-Tests bietet die Code-Coverage eine gute und einfache Möglichkeit zu prüfen, ob durch die definierten Test-Cases alle Code-Pfade in einer Methode wirklich durch Tests ausgeführt werden. Dies hilft beispielsweise dabei, noch fehlende Test-Cases zu identifizieren.

Auch mit manuellen Tests ist es möglich, eine Code-Coverage Analyse durchzuführen um auch hier fehlende Test-Cases zu ergänzen. Das folgende Beispiel zeigt eine mögliche Vorgehensweise.

Zunächst wird davon ausgegangen, dass ein maueller Test spezifiziert ist. Dieser kann z.B. so aussehen:

image

Nun wird ein Unit-Test erzeugt. Im Unit-Test wird eine Test-Methode angelegt die der Main-Methode der zu testenden Anwendung entspricht:

   1: [TestMethod()]
   2: [STAThread]
   3: public void FrmMainConstructorTest()
   4: {
   5:     Application.EnableVisualStyles();
   6:     Application.SetCompatibleTextRenderingDefault(false);
   7:     Application.Run(new FrmMain());
   8: }

 

Anschließend muss geprüft werden, ob die Code Coverage analyse für die gewünschten Assemblies aktiviert ist (Menü Test / Edit Test Run Configurations / Local Test Run)

image

Wird nun der Test gestartet, öffnet sich die Testanwendung. Hier werden nun die einzelnen Test-Schritte gemäß Testspezifikation ausgeführt. Anschließend wird die Test-Anwendung beendet. Dies schließt automatisch auch den Test ab. Nun cann die Code-Coverage ausgewertet werden:

image

Und natürlich lassen sich auch die durchlaufenen und nicht durchlaufenen Code-Zeilen farblich kennzeichnen.

image

Den ganzen Ablauf wird in folgendem Video auch nochmals detailliert gezeigt:

Wednesday, February 18, 2009 11:02:18 PM (Mitteleuropäische Zeit, UTC+01:00)  #    Comments [2] -
Qualitätsmanagement | Testing | VS 2008
Archive
<February 2012>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2012
Thomas
Sign In
Statistics
Total Posts: 560
This Year: 3
This Month: 1
This Week: 3
Comments: 351
Themes
All Content © 2012, Thomas
DasBlog theme 'Business' created by Christoph De Baene (delarou)