Blog Home  Home Feed your aggregator (RSS 2.0)  
artiso Blog - Friday, October 24, 2008
Neues rund um's Thema .Net
 
 Friday, October 24, 2008

Auf Channel 9 gibt es eine ganze Reihe von Videos zu Visual Studio 2010 (Codename Rosario).

Monday, September 29th:
- Announcing Visual Studio Team System 2010

Architecture Day (Tuesday, September 30th):
- Cameron Skinner: Visual Studio Team System 2010 - Architecture
- "Top-down" design with Visual Studio Team System 2010
- "Bottom-up" Design with Visual Studio Team System 2010 Architect
- ARCast.TV - Peter Provost on what’s coming for Architects in Visual Studio Team System

Business Alignment (Wednesday, October 1st):
- Achieving Business Alignment with Visual Studio Team System 2010
- Agile Planning Templates in Visual Studio Team System 2010
- Enterprise Project Management with Visual Studio Team System 2010
- Requirements Management and Traceability with Visual Studio Team System 2010

Software Quality (Thursday, October 2nd):
- Better Software Quality with Visual Studio Team System 2010
- Manual Testing with Visual Studio Team System 2010
- Historical Debugger and Test Impact Analysis in Visual Studio Team System 2010

Team Foundation Server (Friday, October 3rd):
- Brian Harry: Team Foundation Server 2010
- Branching and Merging Visualization with Team Foundation Server 2010
- Enterprise Team Foundation Server Management with Mario Rodriguez
- Team Foundation Server 2010 Setup and Administration
- An early look at Team Foundation Build 2010 with Jim Lamb
- A first look at Visual Studio Team System Web Access 2010
- Update on Team Foundation Server Migration and Synchronization

Visual Studio Team System 2010 Week on Channel 9! | VisualStudio | Channel 9

Friday, October 24, 2008 6:16:54 PM (Mitteleuropäische Zeit, UTC+01:00)  #    Comments [0]    | 
 Thursday, October 16, 2008

Christian Binder hat eine sehr Übersichtliche Darstellung über die verschiedenen VSTS-Sessions auf dem Technical Summit in Berlin zusammengestellt. Die Map stellt nicht nur die dort live vorgestellten Sessions zusammen, soondern auch bereits bestehende und in Kürze erscheinende Webcasts zu dem Thema. Die Map zeigt auch, dass wir versucht haben unsere Inhalte auf dem Technical Summit so aufeinander abzustimmen, dass sowohl EInsteiger als auch fortgeschrittene Anwender sich ein möglichst komplettes Bild von VSTS machen kann. Die WebCast sind thematisch entsprechend eingeordnet und können als Vorbereitung bzw. zur Vertiefung zu den Live-Sessions genutzt werden.

Danke Christian, endlich mal eine übersichtliche Darstellung der verschiendenen Inhalte! 

Tech Summit TFS Track

Was bedeutet was?

image

Christian Binder's Weblog : Alle Visual Studio Teamsystem Session auf dem Technical Summit 2008 im Überblick

Thursday, October 16, 2008 7:41:18 AM (Mitteleuropäische Zeit, UTC+01:00)  #    Comments [0]    |   | 
 Tuesday, October 14, 2008

Microsoft Research hat vor kurzer Zeit PEX zum freien Download veröffentlicht. Hinter diesem unscheinbaren Kürzel verbirgt sich ein Tool das absolut genial und beeindruckend ist und klar mach, warum Microsoft ein research center unterhält. Das Tool verspricht nichts weniger als die automatische Generierung von Unit-Tests und den dazugehörigen Testcases um eine möglichst hohe Code-Abdeckung zu erzielen. Detaillierte Informationen bietet das Whitepaper, wer sich auf die schnelle einen Einblick verschaffen möchte findet einen Überblick im Folgenden (na ja, für einen Überblick ist der Post vielleicht doch ein wenig lang geraden, aber ich konnte mich nicht bremsen vor Begeisterung):

Darf ich vorstellen - PEX

Gegeben sei folgende Methode die getestet werden soll:

   1: public string SimpleTest(int x1, int x2)
   2: {
   3:     if (x1 > x2)
   4:         return "x1 > x2";
   5:     if (x1 < x2)
   6:         return "x1 < x2";           
   7:     else
   8:         return "x1 == x2";
   9: }

Für das versierte Auge eines Entwicklers ist sofort klar, da brauchen wir 3 Testcases um eine vollständige Code-Abdeckung zu erzielen. Mal sehen, was PEX daraus macht. Zunächst mal muss PEX heruntergeladen und installiert sein.  Dann kann man einfach einen "Parameterized Unit Test Stub" erzeugen. Dazu in der Methode rechts klicken und den Befehl aus dem Pex-Menü auswählen.

image

Im folgenden Dialog können Sie verschiedene Parameter angeben. Das wichtigste hier ist das Testprojekt in dem der Stub erzeugt werden soll.

image

Der erzeugte Stub sieht dann so aus:

   1: /// <summary>
   2: /// This class contains parameterized unit tests for Calculation
   3: /// </summary>
   4: [TestClass]
   5: [PexClass(typeof(Calculation))]
   6: public partial class CalculationTest
   7: {
   8:     [PexMethod]
   9:     public string SimpleTest(
  10:         [PexAssumeUnderTest]Calculation target,
  11:         int x1,
  12:         int x2
  13:     )
  14:     {
  15:         string result = target.SimpleTest(x1, x2);
  16:         return result;
  17:         // TODO: add assertions to method CalculationTest.SimpleTest(Calculation, Int32, Int32)
  18:     }
  19:     
  20: }

Bei diesem Stub handelt es such um eine Vorlage für einen parameterisierten Unit-test. Toll, und was lässt sich damit nun machen? Wir können eine "Exploration" starten.

image

Diese Exploration versucht nun Input-Parameter zu finden die zu einer möglichst 100%igen Code-Abdeckung führen. Und hier beginnt nun die Magic von PEX. Ohne unser Zutun findet PEX 3 Kombinationen von Input-Parametern die tatsächlich eine komplette Code-Abdeckung erzielen- WOW! Dazu analysiert PEX wirklich den von uns erstellten Code und kann daraus definieren, mit welchen Input-Parametern die einzelnen noch nicht abgedeckten Zweige erreicht werden können.

image

Und das schönste, PEX baut uns automatisch 3 Unit-Tests die diese Testcases implementieren:

   1: [TestMethod]
   2: [PexGeneratedBy(typeof(CalculationTest))]
   3: public void SimpleTest01()
   4: {
   5:     string s;
   6:     Calculation calculation = new Calculation();
   7:     s = this.SimpleTest(calculation, 1, 2);
   8:     Assert.AreEqual<string>("x1 < x2", s);
   9: }
  10:  
  11: [TestMethod]
  12: [PexGeneratedBy(typeof(CalculationTest))]
  13: public void SimpleTest02()
  14: {
  15:     string s;
  16:     Calculation calculation = new Calculation();
  17:     s = this.SimpleTest(calculation, 1879212556, 1879212556);
  18:     Assert.AreEqual<string>("x1 == x2", s);
  19: }
  20:  
  21: [TestMethod]
  22: [PexGeneratedBy(typeof(CalculationTest))]
  23: public void SimpleTest03()
  24: {
  25:     string s;
  26:     Calculation calculation = new Calculation();
  27:     s = this.SimpleTest(calculation, 256, 254);
  28:     Assert.AreEqual<string>("x1 > x2", s);
  29: }

Diese Unit-Tests können wir nun starten und sehen, dass diese wie erwartet alle erfolgreich sind.

image

Damit haben wir einen Test automatisiert erstellt, der sicherstellen kann, dass diese Methode ihr Verhalten nach Außen für die aktuell definierten Test-Cases nicht verändert. Damit können ungewollte Änderungen an der Methode erkannt und beseitigt werden. Ob die Methode allerdings ihre Aufgabe korrekt erledigt, kann PEX natürlich nicht testen. Haben wir die Funktionsweise einer Methode allerdings einmal validiert, kann PEX nun sehr einfach dieses Verhalten prüfen. Und natürlich eignet es sich auch sehr gut um mögliche Test-Cases zu definieren. Es müssen in diesem Fall dann nur noch die einzelnen Ergebnisse je Test validiert werden.

Ändern wir die Methode ab, so dass sich ihr Verhalten ändert, dann alarmiert uns der entsprechende Test.

Soweit sogut - Und was geht sonst noch?

Wenn wir nun ein gewünschte Änderung der Funktionalität implementieren, wie kann PEX dann damit umgehen? Zunächst würden wir die vorhandenen Tests durchführen, damit wir sicher sind, dass die aktuelle Funktionalität noch korrekt läuft. Dann erweitern wir unsere Methode:

   1: public string SimpleTest(int x1, int x2)
   2: {
   3:     if (x1 > x2 * 2)
   4:         return "x1 > x2 * 2";
   5:     if (x1 > x2)
   6:         return "x1 > x2";
   7:     if (x1 < x2)
   8:         return "x1 < x2";           
   9:     else
  10:         return "x1 == x2";
  11: }
Zeile 3+4 haben wir neu hinzugefügt. Nun starten wir eine neue Exploration und PEX ermittelt einen weiteren Test-Case um diese Funktion ebenfalls abzudecken.
 

image

Schön - darf's noch ein bisschen mehr sein?

Dieses einfache Sample war ja schon sehr beeindruckend. Die Frage, die sich aber natürlich direkt stellt, ist wie weit geht denn das? Wir wollen nun den Schwierigkeitsgrad für PEX schrittweise steigern. Integer-Werte sind ja noch relativ einfach zu handhaben, aber wie sieht's denn beispielsweise mit Strings aus? Hierzu zunächst wieder eine Methode, die wir testen wollen:

   1: public class StringOperations
   2: {
   3:     public string CheckString(string Input)
   4:     {
   5:         if (Input.StartsWith("abc") && Input.Length > 10)
   6:             return Input + " Starts with 'abc' and length > 10"; 
   7:         if (Input.StartsWith("abc"))
   8:             return Input + " Starts with 'abc'";
   9:         if (Input.StartsWith("ABC"))
  10:             return Input + " Starts with 'ABC'";
  11:         return "Unknown pattern";
  12:     }
  13: }

Stubs erzeugen und Exploration starten. Ob PEX wohl solche Operationen wie "StartsWith" und "Length" versteht?

image

Es findet tatsächlich alle erforderlichen Input-Parameter und sogar noch mehr! PEX stell fest, dass unsere Methode beim Übergeben einer NULL-Referenz eine Exception wirft. Und damit nicht genug, PEX kann uns auch einen Vorschlag machen, wie wir unseren Code verbessern können. Dazu im "Pex Exploration Results" - Fenster unter Views "Show suggestions window" aufrufen.

image

image

Durch einen Doppelklick auf den Eintrag am unteren Rand des Bereichs öffnet sich ein Fenster, das die vorgeschlagene Änderung direkt in unseren Code einfügen kann.

image

   1: public string CheckString(string Input)
   2: {
   3:     // <pex>
   4:     if (Input == (string)null)
   5:         throw new ArgumentNullException("Input");
   6:     // </pex>
   7:     if (Input.StartsWith("abc") && Input.Length > 10)
   8:         return Input + " Starts with 'abc' and length > 10"; 
   9:     if (Input.StartsWith("abc"))
  10:         return Input + " Starts with 'abc'";
  11:     if (Input.StartsWith("ABC"))
  12:         return Input + " Starts with 'ABC'";
  13:     return "Unknown pattern";
  14: }

Die Zeilen 3-6 wurden von PEX erzeugt. Natürlich können wir das entsprechende Verhalten im Code direkt ändern und an unsere Vorstellungen anpassen. Vielleicht ist es aber gar keine schlechte Idee, in diesem Fall eine Exception zu werden. Dies ist das Standard-Verhalten von PEX an dieser Stelle. Wird die erwartete Exception nicht mehr geworfen oder eine andere Exception tritt auf, wird dies durch einen fehlgeschlagenen Test angezeigt.

Der nächste bitte!

So nun wollen wir noch einen Schritt weitergehen und sehen, wie PEX mit Listen umgehen kann. Dazu habe ich folgende Testmethode erstellt (über den Sinn einer solchen Methode wollen wir jetzt nicht nachdenken)

   1: int result = 0;
   2: if (list.Count > 10)
   3: {
   4:     foreach (int i in list)
   5:         result += i;
   6: }
   7: else
   8: {
   9:     foreach (int i in list)
  10:         result *= i;
  11: }
  12: return result;

Die Methode bekommt eine Liste von Integer-Werten übergeben. Wenn es mehr als 10 Elemente sind, werden diese addiert, sonst werden die Werte miteinander Multipliziert. Mal sehen, wie PEX mit Listen umgeht.

image

PEX erkennt noch, dass unsere Methode mit Null-References nicht korrekt umgeht, aber dann verließen sie ihn.  Aber freundlicherweise bekommen wir noch einen Hinweis "2 Object Creations". klickt man darauf, dann bekommt man schon mehr Informationen.

image

Aha, PEX kann also eine List<int> nicht erzeugen. Also was tun? Klickt man den unteren der beiden Einträge an, bietet PEX etwas weiter rechts die Möglichkeit eine Factory zu definieren. Eine Factory ist ein Extensibility-Point mit dem PEX beigebracht werden kann mit solchen Objekten umzugehen. Ein Beispiel für eine solche Factory kann so aussehen:

   1: namespace System.Collections.Generic
   2: {
   3:     [PexFactoryClass]
   4:     public partial class ListFactory
   5:     {
   6:         [PexFactoryMethod(typeof(List<int>))]
   7:         public static List<int> Create(int i)
   8:         {