Beim Installieren eines Team Foundation Server 2010 Beta 1 habe ich einen Fehler TF254038 bekommen. Beim Anlegen einer SharePoint Web Application auf dem TFS hat der Wizard behauptet ich hätte die SharePoint Extensions nicht installiert. Ich habe für den TFS und den SharePoint Server zwei getrennte Maschinen. Das Problem lag letztendlich darin, dass die Firewall auf der SharePoint Maschine den Zugriff auf die SharePoint Central Administration (Port 17012) geblockt hat. Nachdem ich den freigegeben habe, lief die Installation problemlos durch.
Wie in diesem Blog bereits an anderen Stellen erläutert, eignet sich das UIA (UI Automation Framework) sehr gut, um UI-Tests aufzubauen. Wer sich mit dieser Möglichkeit beschäftigt wird aber früher oder später auf das Problem stoßen, dass UIA Support bei WinForms Controls nicht flächendeckend gegeben ist, vor allem bei 3rd Party Controls sieht es da oft eher mau aus. Ich habe hier beschrieben, wie man mit einem ServerSide Provider diese Lücken selbst schließen kann. Das Standardvorgehen sieht dabei vor, dass man ein eigenes Control erstellt, das man dann von dem Ausgangscontrol ableitet. Diese Vorgehen ist in der Praxis allerdings nicht unproblematisch. Zum einen muss man die abgeleiteten Controls für jedes neue Release der Ausgangscontrols aktualisieren und zum zweiten ist es nicht gerade schön in einer bestehenden Anwendung alle Controls gegen die abgeleitete Variante austauschen zu müssen. Deshalb möchte ich hier einen alternativen Weg vorstellen. Die Idee beruht darauf, dass die Controls, denen es an Accesibility fehlt jeweils in ein Panel platziert werden und auf diesem Panel dann die entsprechenden Patterns implementiert werden. Das Panel kann die Operationen dann an das Control in seinem Bauch weiterleiten. Ich habe mal ein Beispiel für Janus Calendar Controls gebaut. Zunächst habe ich mir ein UIA-Panel erstellt, von dem ich dann die weiteren Panels für die spezifischen Controls ableiten kann. 1: using System; 2: using System.Drawing; 3: using System.Security.Permissions; 4: using System.Windows.Automation; 5: using System.Windows.Automation.Provider; 6: using System.Windows.Forms; 7: 8: namespace WindowsFormsApplication1 9: { 10: public partial class UIAPanel : Panel, IRawElementProviderSimple 11: { 12: public UIAPanel() 13: { 14: this.BackColor = Color.Yellow; 15: this.Height = 0; 16: this.Width = 0; 17: this.AutoSize = true; 18: } 19: 20: [PermissionSetAttribute(SecurityAction.Demand, Unrestricted = true)] 21: protected override void WndProc(ref Message m) 22: { 23: // 0x3D == WM_GETOBJECT 24: Int32 param = 0; 25: if (Int32.TryParse(m.LParam.ToString(), out param)) 26: { 27: if ((m.Msg == 0x3D) && (param == AutomationInteropProvider.RootObjectId)) 28: { 29: m.Result = AutomationInteropProvider.ReturnRawElementProvider( 30: Handle, m.WParam, m.LParam, (IRawElementProviderSimple)this); 31: return; 32: } 33: } 34: base.WndProc(ref m); 35: } 36: 37: #region IRawElementProviderSimple Members 38: 39: public object GetPatternProvider(int patternId) 40: { 41: if (patternId == ValuePatternIdentifiers.Pattern.Id) 42: { 43: return this; 44: } 45: else 46: { 47: return null; 48: } 49: } 50: 51: public object GetPropertyValue(int propertyId) 52: { 53: if (propertyId == AutomationElementIdentifiers.ClassNameProperty.Id) 54: { 55: return "CalendarPanel"; 56: } 57: else if (propertyId == AutomationElementIdentifiers.ControlTypeProperty.Id) 58: { 59: return ControlType.MenuBar.Id; 60: } 61: 62: if (propertyId == AutomationElementIdentifiers.HelpTextProperty.Id) 63: { 64: return "Help for CalendarPanel"; 65: } 66: 67: if (propertyId == AutomationElementIdentifiers.AutomationIdProperty.Id) 68: { 69: return this.Name; 70: } 71: 72: if (propertyId == AutomationElementIdentifiers.IsEnabledProperty.Id) 73: { 74: return true; 75: } 76: 77: else 78: { 79: return null; 80: } 81: } 82: 83: public IRawElementProviderSimple HostRawElementProvider 84: { 85: get 86: { 87: return AutomationInteropProvider.HostProviderFromHandle(Handle); 88: } 89: } 90: 91: public ProviderOptions ProviderOptions 92: { 93: get 94: { 95: return ProviderOptions.ServerSideProvider; 96: } 97: } 98: 99: #endregion 100: 101: } 102: }
Dieses Panel stellt einen ServerSide Provider zur Verfügung. Wir können nun von diesem Control ableiten und ein entsprechendes Pattern, z.B. das SetValue Pattern implementieren:
1: using System; 2: using System.Windows.Automation.Provider; 3: using System.Windows.Forms; 4: 5: namespace WindowsFormsApplication1 6: { 7: public partial class CalendarPanel : UIAPanel, IValueProvider 8: { 9: private Janus.Windows.Schedule.Calendar control; 10: public Janus.Windows.Schedule.Calendar Control 11: { 12: get 13: { 14: if (control == null) 15: { 16: if (this.Controls.Count > 0 && this.Controls[0].GetType() == typeof(Janus.Windows.Schedule.Calendar)) 17: control = (Janus.Windows.Schedule.Calendar)this.Controls[0]; 18: } 19: return control; 20: } 21: } 22: 23: #region IValueProvider Members 24: 25: public bool IsReadOnly 26: { 27: get 28: { 29: return false; 30: } 31: } 32: 33: public void SetValue(string value) 34: { 35: this.BeginInvoke((MethodInvoker)delegate() 36: { 37: DateTime date = DateTime.Parse(value); 38: Control.SelectionRange = new Janus.Windows.Schedule.DateRange(date, date); 39: }); 40: } 41: 42: public string Value 43: { 44: get 45: { 46: return Control.SelectionRange.End.ToShortDateString(); 47: } 48: } 49: 50: #endregion 51: } 52: }
Wenn wir nun das Calendar_Control nicht direkt auf unserer Form platzieren, sondern in einem solchen CalendarPanel ablegen, können wir eine Automatisierung über die UIA gegen dieses Panel implementieren. Was nun noch optimiert werden soll, ist dass die ganzen Controls nicht händisch in die jeweiligen Panels platziert werden sollen, sondern dies soll nach Möglichkeit automatisiert werden. der Ansatz hierbei ist, dass alle Controls auf der Form beim Laden untersucht werden und für die gewünschten Controls dynamisch entsprechende Panels erzeugt werden sollen, in die dann die Controls platziert werden. Dieser Ansatz bietet zudem den Vorteil, dass man die UIA-Panels nur dann nutz, wenn man UI-Test ausführen möchte. Bei der Release-Version sind diese dann nicht enthalten. Zwar unterscheidet sich dadurch Release und Test-Version geringfügig, jedoch sollten diese Implikationen vernachlässigbar sein, vor allem dann, wenn beim Entwickeln komplett auf die Panels verzichtet wird und diese wirklich nur für die UI-Tests genutzt werden.
Der Code dazu sieht dann so aus:
1: private void PlaceControlsIntoPanel(Control.ControlCollection controls) 2: { 3: Panel uiaPanel; 4: 5: foreach (Control automationControl in controls.OfType<Control>().ToList()) 6: { 7: switch (automationControl.GetType().ToString()) 8: { 9: case "Janus.Windows.CalendarCombo.CalendarCombo": 10: { 11: uiaPanel = new CalendarComboPanel(); 12: break; 13: } 14: case "Janus.Windows.Schedule.Calendar": 15: { 16: uiaPanel = new CalendarPanel(); 17: break; 18: } 19: default: 20: { 21: if (automationControl.HasChildren) 22: { 23: PlaceControlsIntoPanel(automationControl.Controls); 24: } 25: continue; 26: } 27: } 28: uiaPanel.Name = "p_" + automationControl.Name; 29: uiaPanel.Top = automationControl.Top; 30: uiaPanel.Left = automationControl.Left; 31: uiaPanel.Controls.Add(automationControl); 32: automationControl.Top = 0; 33: automationControl.Left = 0; 34: controls.Add(uiaPanel); 35: } 36: }
Wird die Anwendung dann inkl. Test-Client ausgeführt, sieht das so aus:
 Im Juni werden wir beim EMEA-Meeting der Team System User Group Virtual Edition Ed Blankenship als Sprecher haben. Ed ist MVP für Team System und Release Manager bei Infragistics, dem führenden Hersteller von UI-Komponenten. Er wird in seinem Vortrag über die Erfahrungen bei der Einführung von VSTS bei Infragistics berichten. Dabei werden die verschiedenen Bereiche wie Versionsverwaltung, Build Management, Work Item tracking, das Management globaler Teams, automatisiertes Testen und vieles mehr aus einer Anwendersicht beleuchtet. Ein wirklich sehenswerter Erfahrungsbericht aus der Praxis. Weitere Informationen unter www.tsug-ve.com.
Im Team Foundation Server werden Änderungen an den Inhalten der Workitems in einer Historie festgehalten. Diese Historie kann man auf jedem einzelnen Workitem einsehen. Mit einem kostenlosen Excel-Addin können diese Auswertungen auch massenhaft durchgeführt und so über ganze Projekte Auswertungen über die Historie erstellt werden. Dazu wird zunächst ein Zeitraum und ein Intervall ausgewählt (alternativ kann man auch einen bestimmten Zeitpunkt wählen):  Nun werden für jeden gewählten Zeitpunkt die Work Items in dem jeweiligen Zustand in eine Excel-Tabelle eingetragen. Diese kann nun sehr schön über eine Pivot-Tabelle oder ein Pivot-Chart ausgewertet werden um so den zeitlichen Verlauf bestimmter Kennwerte abzubilden.  Natürlich lassen sich solche Ergebnisse auch über das DataWarehouse im TFS ermitteln, jedoch besitzt dieses Tool zwei Vorteile: - Es ist wesentlich einfacher zu bedienen und übersichtlicher, so dass damit auch Ad-Hoc Reporting für Anwender möglich wird.
- Es grift auf alle Workitem-Daten zurück, nicht nur auf die, die im DataWareHouse konfigurierten. Einzige Ausnahme sind Links und Attachments, die in beiden Varianten nicht Teil der Historie sind.
Weitere Informationen und den kostenlosen Download gibtes unter http://www.alm-tools.de/?Product=5 Ein Video das die Fuinktionsweise des Tools demonstriert kann hier agezeigt werden.
Eigentlich versuche ich meinen Blog weitgehend werbefrei zu halten. Diesesmal möchte ich aber doch kurz auf die Seite www.alm-tools.de hinweisen, die mein Arbeitgeber artiso betreibt. Hier haben wir vor Kurzem eine Reihe neuer Tools rund um das Thema TFS und ALM (Application Lifecycle Management) veröffentlich, zum Teil kostenlos. Zudem gibt es hier inzwischen auch ein kleines Archiv mit Videos rund um das Thema das wir kontinuierlich ausbauen.
Mein Kollege Mark Bulmahn hat in einem Screencast ein Problem näher untersucht, das beim Merge in der TFS Source Countrol auftreten kann. Dabei geht es vor allem darum, dass Verschiebe-Operationen im Visual Studio Solution Explorer in der Source Control nicht als Verschiebe-Operation sondern als Delete und Add ausgeführt wird. Das führt dann zu Problemen bei einem späteren Merge.In dem Screencast sieht man, wie dieses Problem vermieden und auch wieder repariert werden kann.
Wenn schon mit Pre-Releases arbeiten, dann richtig habe ich mir gedacht und versucht den Team Foundation Server 2010 Beta 1 auf dem Windows 2008 Server R2 RC zu installieren. Nach einer kurzen Recherche im Internet bin ich auf diesen Blog-Post gestoßen. Mit den Informationen dort ist es mir tatsächlich gelungen, den TFS 2010 Beta1 und VSTS 2010 Beta1 auf dem Win2008R2 RC zu installieren. Damit komme ich nun auch auf meiner Demo-Maschine in den Genuss der Desctop-Experience von Win2008R2 
 Im Mai haben wir bei der TSUG-VE Ian Ceicis als Sprecher zum Thema Projekt Management mit TFS 2010. Er wird in seinem Vortrag die Neuerungen rund um das Workitem-Tracking in TFS 2010 vorstellen. Want to get the skinny on the latest enhancements coming in TFS 2010, come see demos of the updated MSF Agile template, the new Agile workbooks, the new Excel reports, and the Microsoft Project client improvements such as Hierarchical work items, rollups, and project summary tasks. This session will be packed with demos from Beta 1 and will be a great way to start getting familiar with the new tools coming in 2010. Bring your hardest questions, join the conversation, and walk away with the ability to see how your next project will run smoothly if you start using TFS 2010. This month's meeting is being presented by Ian Ceicys. Ian is a member of Microsoft's Global ALM Practice and an active member of the VSTS Rangers. Das Treffen findet am Donnerstag, 21.05.2009 um 19:00 statt. Weitere Infos unter http://www.tsug-ve.com
Unter http://msdn.microsoft.com/en-us/library/dd831853(VS.100).aspx steht inzwischen auch die Dokumentation für das .Net Framework 4 Beta 1 und Visual Studio 2010 Beta 1 zur Verfügung. Für die Beta 1 wird es nur eine Online-Version der Dokumentation geben, eine lokale Installation wird erst mit einer späteren Version verfügbar sein, was sicher bei einer Beta-Dokumentation auch Sinn macht.
Nachdem es bisher nur Gerüchte gab, nun ist es offiziell. Visual Studio 2010 Beta 1 wird noch heute für MSDN-User verfügbar sein. Für die Öffentlichkeit gibt es den Download dann ab Mittwoch.
Diesmal aus einer verlässlichen Quelle (Soma Somasegar, Corporate Vice President Microsofts)
Visual Studio 2010 and .NET FX 4 Beta 1 ships!
Update: Ich habe die Bits inzwischen runtergeladen. Da haben die Jungs wirklich noch einiges reingepackt gegenüber den früheren CTPs.
&
Mit der Version 3 des Design-Tools für WPF und SilverLight, Expression Blend bekommt nun endlich die Unterstützung für den Team Foundation Server um die Source-Dateien in der Versionsverwaltung abzulegen. Hierzu muss ein entsprechendes Hotfix installiert werden. Dann hat man im Project-View zusätzliche Icons die den Auscheck-Status der Dateien anzeigt und im Kontext-Menü befinden sich entsprechende Kommandos für die Versionsverwaltung.
Hinweis: Damit das beim ersten Start auch wirklich funktioniert, muss man im Visual Studio den Team Explorer wenigstens einmal gestartet haben und dort den Server registrieren. Sonst bekommt man die Meldung "Unable to determine workspace" im Expression Blend.
Beim Checkin ist auch die sehr nützliche Funktion zur Verknüpfung von Workitems beim Checkin verfügbar.
Damit kann Expression Blend nun endlich in den Entwicklungs-Prozess von Software-Anwendungen integriert werden und steht nicht nur als separates Design-Tool bereit.
 Nach rund einer Woche ist bereits die Hälfte der Plätze beim .Net Open Space Süd 2009 vergeben. Stand heute haben wir 33 Anmeldungen und es sind ein paar hochkarätige .Net Experten darunter. Wer also noch dabei sein will, sollte nicht zögern, sondern sich gleich auf die Teilnehmerliste eintragen. Wir sehen uns am 11/12. Juli in Ulm!
Auf einer neuen TFS-Instanz hatte ich eben ein seltsames Phänomen. Ich konnte das erste Team-Projekt problemlos anlegen. Dazu verwendete ich einen Team_Explorer mit einer Visual Studio Shell Installation auf dem Server. Als ich allerdings das zweite Projekt anlegen wollte, kam eine Fehlermeldung, dass mir die Berechtigungen auf den Reporting Services fehlen. Seltsam nur, dass es beim ersten Projekt geklappt hat und dazwischen nichts geändert wurde. Mit einem kleinen Trick konnte ich dann doch ein zweites Projekt anlegen, nämlich indem ich alle Projekte aus dem Team-Explorer entfernt habe. Dann konnte ich wieder genau ein neues anlegen. Die eigentliche Lösung für das Problem brachte aber die Installation des SP1 auf dem Server. Dabei ist zu beachten, dass das SP1 für den Team-Explorer nicht Bestandteil des Team Foundation Server SP1 ist, sondern des Visual Studio SP1. Also das Visual Studio SP1 installiert und danach lief es wunderbar.
 Letzte Woche habe ich bei der .Net Developer-Group Ulm einen Vortrag zum Thema “10 Gründe warum Software-Projekte fehlschlagen – und was hilft ALM"?” gehalten. Es gab zu diesem Vortrag eine reihe interessanter Diskussionen. Die Folien gibt’s hier zum herunterladen:
 Bei der TeamConf handelt es sich um eine Konferenz mit dem Focus auf Themen rund um VSTS und TFS. Da durfte ich natürlich nicht fehlen  Leider war mein Vortrag der letzte der Konferenz und dazu noch parallel zum VSTS 2010 Vortrag von Christian Binder. Dennoch fand sich eine interessierte Runde zum Thema “Requirements Management in leichtgewichtigen Prozessen” zusammen. Hier noch meine Folien zum Download:
 Termin: 19.05.2009 - 18:00 Uhr Veranstaltungsort:In den Räumen der artiso solutions GmbH Anfahrtsbeschreibung unter www.artiso.com Referent:Pedro Castelo Branco Lourenço Vortrag:Introducing F# As Developers, when we see a given demand, we always think on how to solve on a very imperative way (first do this, then this, finally that). Why not starting thinking on a more functional level, where we do not need to break one given task into so small imperative steps? This session will introduce Microsoft's new language F#, a typed functional programming language for the .NET Framework that combines the succinctness, expressivity and compositionality of functional programming with the runtime support, libraries, interoperability, tools, and object model of .NET. We'll take a look at why Microsoft is adding the language to the suite of those available on .NET and at some of simple language constructs that make programming in F# a dream. Pedro Castelo Branco Lourenço is a Brazilian guy that moved into Germany to work as Innovation manager at Savcor IT GmbH(http://www.savcor.de), MVP (Microsoft Most Valuable Professional) on C#, Microsoft Certified Professional Developer(Web & Windows), independent consultant to companies that build software using .Net platform, speaker in some well known technical events such as Tech Ed 2005, 2008(Brazil), Community Days, Developers On The Road, União.Net. Bachelor degree in computer science, member of moderator’s team of .Net Raptors community (www.dotnetraptors.com.br). During his free-time he is studying German to make his family life easier!
Zusammen mit Alexander Zeitler organisiere ich den .Net Opensapce Süd 2009. Seit heute ist die offizielle Homepage online und ich freue mich, die Veranstaltung hier ankündigen zu dürfen. Die besten Gespräche hat man fernab von einer festgelegten Agenda, bei einem Kaffee und beim "du". Dort gibt es keine Rollenaufteilung in Sprecher / Zuhörer, Entwickler / Administrator usw. und die Themen finden sich vor Ort ganz von selbst. Das ist die Idee vom .NET Open Space, die sich bereits 2008 in Leipzig bewährt hat. Hier sind alle gleich. Auch die Organisatoren halten sich im Hintergrund und moderieren nur ab und an etwas. Der .NET Open Space Süd 2009 läuft vom 11.07.2009 bis 12.07.2009. Welche Inhalte in dieser Zeit bearbeitet werden, wird vor Ort bestimmt, denn die Veranstaltung ist Open Space. Die Teilnahme ist kostenlos. Die Teilnehmer gestalten das Programm selbst. Erfahrungsaustausch ist das A und O und steht im Vordergrund. Mehr Informationen und Anmeldung unter: http://ulm.netopenspace.de Ich würde mich natürlich freuen, möglichst viele bekannten Gesichter und den einen oder anderen Leser meines Blogs bei diesem Event begrüßen zu dürfen. Ausdrücklich möchte ich betonen, dass dies nicht nur ein Event für Experten ist, sondern dass natürlich auch Teilnehmer willkommen sind, die sich noch nicht für solche halten. An dieser Stelle auch ein herzliches Dankeschön an Torsten Weber und Alexander Groß für die Unterstützung bei der Einrichtung der Website für den .NET Open Space Süd 2009.
 Im zweiten Teil wurde anhand eines kleinen Demos die konkrete Implementierung von WCF-Anwendungen erläutert. Es wurde ein Chat-System auf Basis der WCF erstellt. Das Demo gibt es hier zum Download. Außerdem möchte ich hier noch auf eine Einführung in die WCF hinweisen die man hier findet
 Beim ersten Termin wurden die Grundlagen zu verteilten Anwendungen im allgemeinen und der WCF im speziellen vermittelt.
Eines der coolsten Features in Windows 7 ist für mich der Problem Steps Recorder. Damit lassen sich Benutzeraktionen aufzeichnen und als MHT-File mit Screenshoots ausgeben. Diese Funktion eignet sich sehr gut um z.B. Installationsanleitungen oder auch Dokumentationen von Testdurchläufen zu erstellen. Hierzu wird einfach der Problem Steps Recorder über den Befehl PSR gestartet.  Nach einem Klick auf Start Record werden nun die Benutzeraktionen aufgezeichnet. Heraus kommt dann ungefähr so etwas: Problem Step 15: User left double click on "Name (editable text)" in "WorkItem_Manager_Open_1.0.0_Installer[1]"
Previous Next Problem Step 16: User left click on "Run (push button)" in "Open File - Security Warning"
Previous Next Problem Step 17: User left click on "Next > (push button)" in "artiso Workitem Manager Open"
Diese Aufzeichnungen funktionieren sowohl mit Web- als auch Windows-Anwendungen. Und natürlich können die erzeugten MHT-Files in Word oder anderen Editoren noch bearbeitet werden. So können z.B. überflüssige Zwischenschritte entfernt und Texte editiert werden. Es können auch währen des Aufzeichnungsvorgangs Kommentare erfasst und diesen ein bestimmter Bildausschnitt zugeordnet werden.
 Grade erst wurden die EMEA-Meetings der Team System User Group Virtual Edition ins Leben gerufen, schon können wir mit einem Highlight aufwarten. Für unser April-Meeting konnten wir Brian Harry als Sprecher gewinnen. Brian wird über die Internal Adoption von VSTS sprechen. Brian ist Technical Fellow und Manager der Product Unit für den team Foundation Server. Also gleich als Mitglied registrieren und am 16. April dabei sein! Weitere Informationen zum Meeting gibt’s unter www.tsug-ve.com.
 | Am 07. April um 18:00 Uhr findet das nächste Treffen der .Net Developer-Group Ulm statt. Diesesmal geht es im Rhamen der Microsoft Usergroup-Tour um das Thema Silverlight. Referent: Philipp Bauknecht Vortrag: Web & Silverlight Der Referent Philipp Bauknecht zeigt anhand eines E-Commerce-Szenarios, welche neuen Möglichkeiten in Silverlight und den Microsoft-Webtechnologien stecken. Er gibt Einblicke in die Bildbearbeitung mit Expression Design und in das Arbeiten und Programmieren mit Expression Blend. Weitere Themenschwerpunkte sind die Veröffentlichung von Videos sowie die wesentlichen Silverlight-Entwicklungsgrundlagen in Visual Studio. Anhand praktischer Beispiele demonstriert Philipp Bauknecht, wie sich die letzte Meile zum Anwender mithilfe von Silverlight durch interaktive Methoden überwinden lässt. Weitere Infos finden Sie hier… Freue mich auf zahlreiche Teilnehmer. Es gibt diesesmal wieder einen leckeren Imbiss der von der Fa. SOS Software Services gesponsort wird. |
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
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. 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”.
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.
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!
Letzte Woche war ich als Trainer beim Team System Camp. Eine wirklich bemerkenswerte Veranstaltung! Schon der Veranstaltungsort selbst war bemerkenswert. Das Häckers Kurhotel in Bad Ems stellte einen durchaus würdigen Rahmen für die Veranstaltung dar und auch der Seminarraum hatte durchaus Stil: Die Verpflegung war dem Ambiente angemessen, Mittags und Abends ein vorzügliches 3-Gänge-Menü und auch das Rahmenprogramm passte. Mit Kart-Fahren, Casino-Besuch und weiteren Aktivitäten konnte ein paar Momente entspannt werden. Das war auch dringend nötig. Denn trotz all dieser Annehmlichkeiten kamen natürlich die Inhalte nicht zu kurz. Zwei Trainer auf 5 Teilnehmer ist sicher schon ein ungewöhnlicher Schnitt. Aber dass die Trainings von 9:00 Uhr bis 23:00 gehen ist schon heftig. Also wurde nach dem Kart-Fahren noch was gegessen und dann ging’s im Seminar-Raum weiter. So konnten die Teilnehmer sicher einen sehr guten Überblick über den Team Foundation Server und VSTS bekommen. Und durch die kleine Gruppengröße konnte auch auf individuelle Fragen ausführlich eingegangen werden. Mir hat’s jedenfalls viel Spaß gemacht und bin beim nächsten mal gerne wieder dabei.
Für alle die entweder in der Nähe von Wien leben oder die entsprechend großes Interesse am Thema VSTS haben um diese schöne Stadt auch mal zu besuchen, hier eine Ankündigung: Am 8. Mai 2009 wird im Microsoft Innovation Center (MIC) in Wien der Office (VSTO) Community Day statt finden. Hierbei geht es 1 Tag lang rund um Office Business Applications. Die Veranstaltung wird von Lars Keller und Mario Meir-Huber geführt. Die Themen sind: · Einführung in die VSTO · OpenXML: Das neue Office Format · VSTO Deployment · Sharepoint Workflows und Integration · Interaktionen in der "Office-Welt" mit .NET · Office plus Services Die Veranstaltung ist frei zugänglich, jedoch gibt es eine Limitierung auf 35 Teilnehmer. Anmelden kann man sich in dem extra für das Event aufgesetzten Wiki (http://www.vsto-taskforce.de/wikis/ocd/teilnehmer.aspx).
Die Integration von Visual Studio 2005 / 2008 mit dem TFS ist ideal gelöst. Jedoch gibt es auch noch andere Entwicklungs-Plattformen die keine direkte Integration mit dem Team-Explorer erlauben wie z.B. ältere Visual Studio Versionen und leider auch immer noch das SQl Server Management Studio. Diese IDEs überstützen doch recht häufig den sog. MSSCCI-Standard und es gibt bereits seit längerer Zeit einen entsprechenden MSSCCI-Provider für den TFS 2008. Dieser hatte bisher immer noch den nachteil, dass er reine Sourcecontrol Features unterstützt hat und z.B. das Verknüpfen von Workitems beim Checkin nicht möglich war. In der neuesten Version ist dies nun auch möglich und somit ist auch bei IDEs die den Team Explorer nicht integrieren ein komfortables Arbeiten mit dem TFS möglich. Ich habe hier mal ein Beispiel für das SSMS 2008. Zunächst muss der TFS MSSCCI-Provider unter Optionen eingestellt werden. Legt man nun ein Datenbankprojekt an, dann kann man das in gewohnter Art und Weise mit der Source Control verbinden und man erhält Fenster “Pending Checkins”. Führt man hier nun den Checkin aus, kommt der aus dem Team-Explorer bekannte Dialog Hier können nun z.B. Checkin-Kommentare angegeben oder Workitems verknüpft werden. Sogar die Checkin-Plicies funktionieren hier wie gewohnt. Damit ist ein komfortables und problemloses Arbeiten auch mit solchen Umgebungen möglich, die den Team-Explorer nicht direkt integrieren. Und damit wieder ein Grund mehr, nun endlich auf den TFS zu setzen und SourceSafe und Konsorten endlich in Rente zu schicken.
 Bei der Team System Usergroup – Virtual Edition (TSUG-VE) handelt es sich um eine weltweite Online-Community die sich auf die Themen Visual Studio Team System und Team Foundation Server konzentriert hat. Die Treffen finden dabei zeitgleich in SecondLife und LiveMeeting statt. SecondLife bietet den Vorteil, die sozialen Aspekte einer Community besser in der Online-Welt abzubilden, LiveMeeting wird als Präsentationssystem genutzt. Die virtuellen Treffen unterscheiden sich vom Ablauf und Inhalt kaum von denen entsprechender Offline-Communities. Während und nach den Vorträgen können ganz normal Fragen gestellt werden. Die Vorträge werden aufgezeichnet und stehen Mitgliedern im nachhinein im LiveMeeting-Portal zur Verfügung. Um die Vortragszeiten für die Teilnehmer rund um den Globus komfortabler zu gestalten, wurde nun eine europäische Sektion der TSUG-VE ins Leben gerufen. Diese Sektion organisiert Meetings in einer komfortablen Zeit für die EMEA-Zone (19:00 Uhr deutscher Zeit). Natürlich steht den Mitgliedern jederzeit die Möglichkeit offen, an den Treffen der US-Sektion oder für den Bereich Asian-Pacific (momentan im Aufbau) teilnehmen zu können oder die Videos nachträglich abzurufen ohne sich hierfür separat registrieren zu müssen. Alle Treffen werden in englischer Sprache abgehalten. Die Leitung der EMEA-Zone habe ich übernommen und würde mich freuen, in Zukunft mehr Mitglieder aus dem Europa begrüßen zu dürfen. Kritik und Anregungen zur Organisation sind sehr willkommen, da wir im Moment noch dabei sind Erfahrungen im Betreiben einer Online-Community sammeln.
 VISfire sit eine Charting-Komponente für Silverlight und WPF. Das coole daran ist, dass die Charts animiert werden können. Einen schnellen Eindruck bekommnt man über die Silverlight Chart Gallery. Die componente ist unter GPL und einer kommerziellen Lizenz verfügbar.
Wie so oft lautet die Antwort es kommt darauf an. Un hier bietet die Seite ShineDraw eine gute Vergleichsmöglichkeit. In der Gallery befinden sich zahlreiche Beispiele die sowohl in Silverlight als auch in Flash implementiert sind. Da kann man nicht nur das Ergebnis in beiden Varianten vergleichen sondern auch den Code der in der jeweiligen Technologie erforderlich ist. Darüber hinaus kann man sich den einen oder anderen effekt abschauen und sieht auch gleich wie der implementiert wird. Der Quellcode ist unter der GNU General Public License, Version 3 bereitgestelt. http://www.shinedraw.com/flash-vs-silverlight-gallery/
 Die Initiative Clean Code Developer (CCD) (http://www.clean-code-developer.de/) hat sich zum Ziel gesetzt bestimmte Grundsätze bei der Entwicklung von Software bei den Entwicklern besser zu verankern. Bei diesen Grundsätzen handelt es sich um Prinzipien, Regeln und Praktiken deren Einhaltung zu qualitativ höherwertigem Code führt. Grundsätzlich ist eine Schrittweise Einführung dieser Prinzipien, regeln und Praktiken unterteilt in Grade vorgesehen. Zu jedem Grad gibt es ein farbiges Armband, das den Träger zum Einen als CCD ausweist und ihn zudem stets daran erinnert diese Grundsätze in seiner täglichen Arbeit zu befolgfen. Mit Sefan Lieser und Ralf Westphal stehen hinter diesem Projekt zwei ausgewiesene Experten. Die .Net Developer-Group Ulm (www.dotnet-ulm.de) möchte diese Aktion unterstützen und ruft seine Mitglieder auf sich zu beteiligen. Beim nächsten Treffen am 19.03.09 wird diese Aktion im Detail vorgestellt und es besteht die Möglichkeit die Armbänder zu einem vergünstigten Preis zu erwerben. Zudem ist angedacht, dass sich die beteiligten regelmäßig nach den UG-Meetings austauschen und gegenseitig über Erfahrungen berichten und die Konzepte des CCD miteinander diskutieren. Natürlich freue ich mich auf eine rege Teilnahme und natürlich sind Gäste gerne willkommen. Nähere Infos unter http://www.dotnet-ulm.de/Cleancodedeveloper.aspx
 Bei unserem nächsten Treffen am 19.03 haben wir Gregor Biswanger und Robert Walter zu Gast. Diese werden in ihrem Vortrag verschiedene Aspekte zu Test Driven Development beleuchten. Nähere Infos gibts hier: http://www.dotnet-ulm.de/Treffen.aspx#19032009
 Am 16.03.09 geht ein neuer Webcast von mir online mit dem Thema "Team Build mit Custom Build Tasks erweitern". Ich möchte hier schon mal die entsprechenden Infos veröffentlichen. In TeamBuild lassen sich eigene Build-Task integrieren. Diese können sehr einfach erstellt werden. Hierzu wird eine Klasse erstellt und diese von Task abgeleitet. Im folgenden Beispiel wird ein Build-Task erstellt, der im Rahmen des Builds die Version der Anwendung setzt. Und zwar soll hier die Build-Nummer in der Versionsnummer der Assembly abgebildet werden. Dies bietet Vorteile, wenn zu einer bestimmten Anwendungsversion der entsprechende Build identifiziert werden soll. 1: using System; 2: using System.Collections.Generic; 3: using System.Text; 4: using Microsoft.Build.Utilities; 5: using Microsoft.Build.Framework; 6: 7: namespace Artiso.BuildTasks 8: { 9: /// <summary> 10: /// Creates a AssemblyVersion out of a BuildNumber 11: /// </summary> 12: /// <remarks> 13: /// AssemblyVersion.Minjor and AssemblyVersion.Minor will be defined fiexed in 14: /// the Build-Script. If the BuildNumber is Dev_Versioning_20090305.4 we use 15: /// two digit year and month for AssemblyBuildNumber and day and 3 digit BuildRevision 16: /// for AssemblyRevision. BuildRevisio 17: /// </remarks> 18: /// <example> 19: /// Dev_Versioning_20090305.4 => xx.yy.0903.05004 20: /// </example> 21: public class ExtractRevision : Task 22: { 23: #region [rgn] Fields(3) 24: private string buildRevision; 25: private string buildVersion; 26: private string buildNumber; 27: #endregion 28: 29: #region [rgn] Properties(3) 30: /// <summary> 31: /// Input Build Number 32: /// </summary> 33: [Required] 34: public string BuildNumber 35: { 36: set { buildNumber = value; } 37: } 38: 39: /// <summary> 40: /// Returns the sortened date of the build 41: /// </summary> 42: [Output] 43: public string BuildVersion 44: { 45: get { return buildVersion; } 46: } 47: 48: /// <summary> 49: /// Returns the Build Revision (number of build at this day 50: /// </summary> 51: [Output] 52: public string BuildRevision 53: { 54: get { return buildRevision; } 55: } 56: #endregion 57: 58: #region [rgn] Methods(1) 59: public override bool Execute() 60: { 61: buildVersion = "0"; 62: buildRevision = "0"; 63: 64: if (buildNumber != null && buildNumber.Contains(".")) 65: { 66: string[] buildNumberParts = buildNumber.Substring(buildNumber.LastIndexOf('_')+1).Split('.'); 67: 68: // Dev_Versioning_20090305.4 -> 0903.02005 69: // use year (2 digits) and mont for buildversion 70: buildVersion = buildNumberParts[0].Substring(2, 4); 71: 72: // use day and number of build in this day for build revision 73: buildRevision = buildNumberParts[0].Substring(6) + buildNumberParts[1].PadLeft(3, '0'); 74: } 75: return true; 76: } 77: #endregion 78: } 79: }
Das Property BuildNumber wird als Input-Parameter verwendet und mit dem Attribut [Required] versehen. Darüber kann die BuildNumber in unseren Task übergeben werden. Durch das Attribut [Output] werden die beiden Properties BuildVersion und BuildRevision als Rückgabewerte definiert. Beim Ausführen des Builds wird die Methode Execute aufgerufen. Hier werden nun aus der Build-Number die entsprechenden Informationen extrahiert und diese dann in BuildVersion und BuildRevision zurückgeschrieben. Dies ist natürlich nur ein einfaches Beispiel, aber mit diesen Grundlagen können nun beliebige Build-Tasks definiert werden. Im nächsten Schritt schauen wir uns an, wie wir diesen Custom Build Task nun in unseren Build-Prozess einbinden. Hierzu kopieren wir zunächst die Assembly in einen entsprechenden Ordner. Hier bietet sich an unter c:\Program Files\MSBuild einen entsprechenden Ordner anzulegen und dort die Assemblies abzulegen.
Nun muss das Build-Script entsprechend angepasst werden. Diese liegt in der Quellcode-Verwaltung und muss zum Bearbeiten zuerst aus- und danach wieder eingechecked werden. Um diesen Vorgang zu vereinfachen empfehle ich die TFS Sidekicks (http://www.attrice.info/downloads/index.htm) die direkt im Kontextmenü des TeamExplorers entsprechende Kommandos einfügt. Das nun ausgecheckte PROJ-File kann nun bearbeitet werden.
1: <?xml version="1.0" encoding="utf-8"?> 2: <!-- DO NOT EDIT the project element - the ToolsVersion specified here does not prevent the solutions 3: and projects in the SolutionToBuild item group from targeting other versions of the .NET framework. 4: --> 5: <Project DefaultTargets="DesktopBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5"> 6: 7: <!-- Do not edit this --> 8: <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets" /> 9: <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/> 10: 11: <UsingTask AssemblyFile="$(MSBuildExtensionsPath)\ArtisoBuildTasks\ArtisoBuildTasks.dll" 12: TaskName="ExtractRevision"/> 13: 14: <PropertyGroup> 15: <!-- Assembly version properties. Adjust here Major and Minor Version--> 16: <AssemblyMajorVersion>1</AssemblyMajorVersion> 17: <AssemblyMinorVersion>3</AssemblyMinorVersion> 18: <AssemblyBuildNumber>1</AssemblyBuildNumber> 19: <AssemblyRevision>1</AssemblyRevision> 20: </PropertyGroup> 21: ...
In Zeile 11 wird unser BuildTask entsprechend registriert. In Zeile 9 werden noch weitere Build-Tasks registriert. Hier gereicht es uns zum Vorteil, dass Team-Build auf MSBuild basiert. D.h. es können entsprechende Tasks für MSBuild problemlos integriert werden. Diese gibt es in großer Zahl für sehr viele Anwendungsbereiche zum großen Teil frei Verfügbar zum Download. Wir verwenden hier die MSBuild Community Tasks ( http://msbuildtasks.tigris.org/). Wir werden aus diesem Paket Aktionen verwenden.
In den Zeilen 14 bis 20 wird eine sog. PropertyGroup angelegt. Darin werden einzelne Properties definiert und mit Default-Werten vorbelegt. Diese Properties lassen sich mit Variablen innerhalb eines Software-Codes vergleichen. Die AssemblyMajorVersion und AssemblyMinorVersion werden hier festgelegt. AssemblyBuildNumber und AssemblyRevision werden wir im weiteren Verlauf überschreiben.
Am Ende des Scripts direkt vor dem schließenden </Project>-Tag wird nun ein Target-Block eingefügt.
1: ... 2: <Target Name="AfterGet"> 3: <ItemGroup> 4: <AssemblyInfoFiles Include="$(SolutionRoot)\**\assemblyinfo.cs" /> 5: </ItemGroup> 6: 7: <Message Text="Get Revision Number from BuildNumber "$(BuildNumber)"." /> 8: <ExtractRevision BuildNumber="$(BuildNumber)"> 9: <Output TaskParameter="BuildRevision" 10: PropertyName="AssemblyRevision" /> 11: <Output TaskParameter="BuildVersion" 12: PropertyName="AssemblyBuildNumber" /> 13: </ExtractRevision> 14: 15: <!-- Update all the assembly info files with generated version info --> 16: <Message Text="Modifying AssemblyInfo files under "$(SolutionRoot)"." /> 17: <Attrib Files="@(AssemblyInfoFiles)" Normal="true" /> 18: <FileUpdate Files="@(AssemblyInfoFiles)" 19: Regex="AssemblyVersion\(".*"\)\]" 20: ReplacementText="AssemblyVersion("$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision)")]" /> 21: <FileUpdate Files="@(AssemblyInfoFiles)" 22: Regex="AssemblyFileVersion\(".*"\)\]" 23: ReplacementText="AssemblyFileVersion("$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision)")]" /> 24: <Message Text="AssemblyInfo files updated to version "$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision)"" /> 25: </Target> 26: 27: </Project>
Über den Namen des Target-Blocks mit "AfterGet" wird festgelegt, dass dieser Block ausgeführt wird, nachdem der Build-Prozess die Quelldateien aus der Versionsverwaltung geholt hat. Genau zu diesem Zeitpunkt wollen wir unsere Versionierung anpassen. In den Zeilen 3 bis 5 erstellen wir eine ItemGroup die alle assemblyinfo.cs Dateien unserer Solution enthält. In diesen Dateien wollen wir die Version anpassen. In Zeile 7 wird eine Meldung in das Build-Log geschrieben. Dies ist hilfreich, um Fehler im Ablauf des Scriptes besser einordnen zu können.
In den Zeilen 8 bis 13 wird nun unser Build-Task aufgerufen. Wir übergeben die Buildnummer $(BuildNumber) in den Parameter BuildNumber und lesen die Output-Parameter aus und schreiben diese in AssemblyRevision bzw. AssemblyBuildNumber (die Properties die wir weiter oben definiert hatten). In Zeile 17 heben wir den Schreibschutz der AssemblyInfo-Dateien auf und in den folgenden Zeilen wird mit Hilfe eines Ersetzen-Vorgangs die Version in den AssemblyInfo-Dateien ersetzt. Für diese Aktionen nutzen wir die Community Build Tasks.
Damit können wir nun die Version unserer Anwendung bei jedem Build entsprechend setzen.
In einem nächsten Schritt wollen wir den Build-Task nun noch erweitern um das Build-Result in einer ZIP-Datei zu verpacken und diese anschließend per Mail zu versenden. Auch hierbei greifen wir auf die MSBuild Community Tasks zurück. Das entsprechende Target-Tag fügen wir einfach nach dem zuvor definierten ein. Als Name geben wir "AfterCompile" an so dass diese Aktionen nach dem Kompilieren ausgeführt werden. 1: <Target Name="AfterCompile">
2: <CreateItem Include="..\Binaries\Release\**\*.*" Exclude="..\Binaries\Release\**\*.pdb;..\Binaries\Release\**\*codeanalysis*"> 3: <Output ItemName="ZipFiles" TaskParameter="Include"/> 4: </CreateItem> 5: 6: <Message Text="Zipping Buildresult to \\tfs\deploy\BuildDemo\BuildDemo_$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision).zip" /> 7: 8: <Zip ZipFileName="\\tfs\deploy\BuildDemo\BuildDemo_$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision).zip" 9: Files="@(ZipFiles)" 10: WorkingDirectory="..\Binaries\Release\"/> 11: 12: <Mail SmtpServer="tfs" 13: To="tschissler@tfs" 14: From="build@tfs" 15: Subject="BuildDemo v$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision) released" 16: Body="A new version of the BuildDemo was released. Please find the newest files attached to this mail. You can also download them from the download folder." 17: Attachments="\\tfs\deploy\BuildDemo\BuildDemo_$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision).zip"/> 18: </Target>
Hier sammeln zunächst alle Dateien aus dem Build-Drop-Verzeichnis exklusive der PDB- und Codeanalyse-Dateien In Zeilen 8-10 werden diese Dateien in ein ZIP-File verpackt dem wir im datei-Name die Version mitgeben. Anschließend versenden wir eine e-Mail der wir dieses ZIP-File als Attachment anhängen.
Als zweite Variante wollen wir im Rahmen des Builds ein Click-Once Paket erstellen. Die Herausforderung bei der Erstellung des ClickOnce-Paketes ist dass dort die Deployment-Url hinterlegt werden muss. Vor allem wenn verschiedene Pakete für unterschiedliche Kunden erstellt werden sollen, ist dies nur durch eine Automatisierung im Rahmen des Builds sinnvoll handelbar. Hierzu ersetzen wir den AfterCompile-Target durch folgendes Script:
1: <Target Name="AfterCompile"> 2: <!-- Publish using ClickOnce --> 3: <Message Text="modify Publish directory for $(SolutionRoot)" /> 4: <!-- Update directory where to publish the project --> 5: <ItemGroup> 6: <ProjectFiles Include="$(SolutionRoot)\Source\Dev\BuildDemo\BuildDemo.csproj" /> 7: </ItemGroup> 8: <PropertyGroup> 9: <PublishDir>\\tfs\Deploy\BuildDemo\ClickOnce\</PublishDir> 10: <InstallUrl>\\tfs\Deploy\BuildDemo\ClickOnce\</InstallUrl> 11: </PropertyGroup> 12: <Attrib Files="@(ProjectFiles)" Normal="true" /> 13: <FileUpdate Files="@(ProjectFiles)" 14: Regex="<PublishUrl>.*</PublishUrl>" 15: ReplacementText="<PublishUrl>$(PublishDir)</PublishUrl>" /> 16: <FileUpdate Files="@(ProjectFiles)" 17: Regex="<InstallUrl>.*</InstallUrl>" 18: ReplacementText="<InstallUrl>$(InstallURL)</InstallUrl>" /> 19: 20: <MSBuild Projects="@(ProjectFiles)" 21: Properties="PublishDir=$(PublishDir);ApplicationVersion=$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(AssemblyBuildNumber).$(AssemblyRevision)" 22: Targets="Publish" /> 23: 24: </Target>
In den Zeilen 5 bis 7 lesen wir das csproj-File der Anwendung in eine ItemGroup. Anschließend definieren wir zwei Properties für PublishDir und InstallUrl. Diese werden dann über eine Ersetzung in die csproj-Datei eingefügt. Anschließend wird ein MSBuild-Task gestartet der das ClickOnce-Paket erstellt und an der angegebenen PublishDir und mit der Versionsnummer veröffentlicht.
Das Ganze wird in dem genannten Webcast Live demonstriert. Über Feedback würde ich mich sehr freuen.
Details zur Veranstaltung: Team Build mit Custom Build Tasks erweitern [1032405249] - Microsoft Deutschland GmbH
Letzte Woche war ich auf dem MVP-Summit in Seattle. Für mich war es die erste Veranstaltung dieser Art und so wusste ich nicht genau, was mich erwarten würde. Ich wurde aber auf jeden Fall positiv überrascht. Es war für mich eine Woche voller neuer Infos und Eindrücke und es war auch sehr cool, die anderen Team System MVPs persönlich zu treffen und sich mit denen auszutauschen. Gerade im Bereich Team System tut sich momentan extrem viel und so hatten wir ein Non-Stop Programm und um VSTS 2010. Non Stop heißt, dass es bereits am Sonntag Nachmittag mit einer MVP 2 MVP Session losging, wo einige MVPs Erfahrungen aus ihrer Praxis darstellten. Das war extrem interessant und ich konnte viele neue Ideen mitnehmen. Am Montag und Dienstag hatten wir dann von 8:00 bis 18:00 Uhr volles Programm. Verschiedene Mitglieder der Product-Group stellten die einzelnen Bereiche von VSTS 2010 vor. Volles Programm heißt in diesem Fall Sessions ohne Pause (wir hatten selbst Lunch-Sessions, wo man sich am Buffet etwas zu Essen holte und dann sich setzte um der aktuellen Session zu folgen). Neno hat wirklich ein anspruchsvolles Programm für uns zusammen mit der Product-Group zusammengestellt. Da war wirklich extrem viel Content drin. Am Mittwoch waren dann Key-Notes angesagt, die ich allerdings etwas enttäuschend fand und damit wirklich keine Zeit verschwendet war, hatten wir am Mittwoch Nachmittag nochmals Sessions bei denen wir mit Sam Guckenheimer über die zukünftige Entwicklung diskutierten. Eine wirklich extrem interessante Woche mit vielen neuen Eindrücken. Es wird wohl etwas dauern, bis ich das alles verarbeitet habe, der geneigte Leser wird aber dann die Ergebnisse an dieser Stelle lesen können Im Moment kann ich das Ganze nur so zusammenfassen: VSTS 2010 is a realy big, big thing! Hier noch ein paar Impressionen: Blick von der Space Needle auf Seattle  Die Team-System MVPs  Sam Guckenheimer  Brian Harry Karaoke mit Live-Band bei der Party Steve Balmer bei seiner Key-Note
Gestern und heute hatte ich auf der BASTA zwei Vorträge. Hier die Folien dazu:
 Ich bin reichlich spät dran, die VSOne ist schon seit einer Woche vorbei. Hier aber nun endlich meine Folien zu meinen Vorträgen
 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
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.
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.
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.
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?
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.
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:
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.

Hier hatte ich beschrieben, wie man die Test-Results aus Visual Studio nach Excel übertragen kann. Heute möchte ich ein Tool vorstellen, das es erlaubt, TRX-Files nach HTML zu konvertieren. Zunächst speichert man das Test-Result in ein TRX-File. Dies geht über den Button "Export Test Run Results". Anschließend kann man mit dem Tool trx2html das HTML-File erstellen. trx2html ist ein Open-Source Projekt von CodePlex. Es wird als Commandozeilen-Tool ausgeführt und als Parameter wird einfach das TRX-File angegeben. Als Ergebnis wird nun ein HTML-File erstellt das die Testergebnis entsprechend dokumentiert und auch einige Drill-Down-Funktionen bietet: Durch einen Klick auf das rote Kreis-Icon neben einem der Test kann z.B. ein Stack-Trace eingeblendet werden. trx2html - Home
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: 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)
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:
Und natürlich lassen sich auch die durchlaufenen und nicht durchlaufenen Code-Zeilen farblich kennzeichnen.
Den ganzen Ablauf wird in folgendem Video auch nochmals detailliert gezeigt:
 Beim nächsten Treffen der .Net Developer-Group Ulm dürfen wir diesesmal Dariusz Parys begrüßen, der zum Thema “Architektur der Datenanbindungsschicht, insbesondere ADO.NET Data Services und Entity Framework” spricht. Der Abstract verspricht schon mal einen sehr spannenden Abend: LINQ to SQL, ADO.NET, Entity Framework, Entity Data Model, REST mit ADO.NET Data Services oder Serialisierung mit WCF ? – neben einem Überblick über die Alternativen und detailliertere Darstellung des Entity Frameworks wird darauf eingegangen, welche Kriterien beim O/R-Mapping zur Bewertung zur Verfügung stehen und diskutiert, welcher Nutzen darin liegt, die Datenanbindung von einer technischen Ebene auf eine logische zu heben. Ích glaube das dürfte ein Themengebiet sein mit dem im Moment jeder Entwickler in irgendeiner Weise käpft und so dürfte sich Dariusz schon mal auf eine ganze Reihe von Fragen einstellen (Mir selbst fallen da schon eine ganze Reihe ein). Wer also Interesse an dem Thema hat, ist herzlich eingeladen am Dienstag 17.02.2008 um 18:00 zu uns zu kommen. Weitere Infos unter: http://www.dotnet-ulm.de
In manchen Fällen ist es wünschenswert, eine Liste mit den Tests aus einem Projekt auszudrucken. Leider gibt es hierzu in Visual Studio keine direkte Funktion, aber ein kleiner Trick hilft hier: 1.) Im TestView die gewünschten Spalten einblenden 2.) Gewünschte Tests markieren und dann im Kontext-Menü "Copy" auswählen 3.) In Excel einfügen, fertig! Das selbe funktioniert übrigens auch aus den Test Results, leider ohne Icons :-( 
Als Blogger freut man sich natürlich immer über Kommentare. Das ist bei diesem Medium eine der wenigen Möglichkeiten Feedback zu bekommen. Und nun musste ich feststellen, dass auf meinem Blog leider seit einger Zeit die Kommentare nicht mehr richtig zugestellt werden. Dafür ein großes Entschuldigung an alle, die in letzte Zeit sich die Mühe gemacht haben und meine Beiträge kommentiert haben. Sorry, das ihr keine Antwort erhalten habt. Lasst euch nicht entmutigen, ich freue mich über jeden Kommentar und jetzt sollten die auch wieder bei mir ankommen.
Die Team System User Grroup - VE ist eine virtuelle Usergroup die zwei mal im Monat ein Treffen hat in deren Rahmen Vorträge rund um das Thema Team System gehalten werden. Die Treffen finden virtuell in Second Life und über Live Meeting statt. Für Europäer ist das jeweils zweite Treffen zeitlich günstig am Samstag Nachmittag. Team System User Group - Virtual Edition
Auf MSDN gibt es einen neuen Bereich zu Team System. Die Seite ist in einer ersten Iteration veröffentlicht und wird nun kontinuierlich mit weiterem Content ergänzt. Hier sind die Inhalte wesentlich übersichtlicher aufbereitet als auf den alten Seiten. Wer also mit Team System arbeitet oder das vorhat, einfach mal vorbeischauen. Feedback zu der Seite ist sehr willkommen und kann hier abgegeben werden. Team System Home auf MSDN
 Endlich gibt es von PEX nun auch eine kommerziell nutzbare Lizenz. Bisher stand nur eine Academic License zur Verfügung, mit der nur “gespielt” werden durfte. Aber welche Aussagekraft hat denn eine Bewertung des Tools mit Demo-Projekten? Jetzt kann man PEX nun endlich auch auf Real-World-Projekte loslassen. http://research.microsoft.com/en-us/projects/pex/downloads.aspx
Bisher war für mich das Pflegen meiner verschiedenen Signaturen im Outlook immer ein Horror. Wenn ein neuer Rechner eingerichtet wurde, musstden die Signaturen wieder mühsam angelegt werden und wenn es Änderungen gab, dann grauste es mich schon davor, diese auf allen Instanzen anzupassen. Dank Lars kenne ich nun aber einen einfacheren Weg. Die Signaturen werden nämlich einfach im Filesystem abgelegt und zwar unter %UserProfile%\AppData\Roaming\Microsoft\Signatures. Diese Files lassen sich einfach auf einen neuen Rechner kopieren (sogar bei laufendem Outlook sind die Signaturen dann sofort verfüpgbar!) oder sie können zwischen mehreren Rechnern einfach synchronisiert werden. Super cool. Vielen Dank Lars, du hast mir das Leben wirklich erleichtert!
Inzwischen gibt es eine verstärkte Diskussion, ob der Windows 2008 Server nicht die bessere Workstation ist. Sicher hängt das vom jeweiligen Einsatzgebiet ab. Bei mir war es so, dass ich für den Team Foundation Server einen Server als Betriebssystem auf meinem Demo-Rechner benötigt habe. Dabei wollte ich aber nicht auf den Komfort und das Design von Vista verzichten und auch Features wie z.B. den Sidebar nutzen. Die erste gute Nachricht ist, dass man Win2008 so anpassen kann, dass es sich optisch kaum von Vista unterscheiden lässt und die zweite gute Nachricht ist, dass es mit Hilfe eines kleinen Tools ganz einfach ist und schnell geht. Selbst Aero ist damit möglich. http://www.win2008workstation.com/wordpress/2008/07/17/windows-server-2008-workstation-converter/
In den letzten Wochen war ich recht viel mit Vorträgen auf Tour. Inzwischen hat sich eine stattliche Anzahl von Vortragsthemen angesammelt. Unten sieht man eine Übersicht. Wer Interesse hat, dass ich einen Vortrag halte, darf sich gerne bei mir melden. Über das INEATA Speaker Bureau bin ich für INEATA UserGroups auch kostenlos zu buchen. Ansonsten würde ich mich auch über Feedback freuen. Sollte ich noch ein Thema mit aufnehmen, wer hat schon einen Vortrag von mir gehört und wie hat er gefallen etc. | Titel | Dauer | Abstract | | Qualitätsmanagement mit VSTS und TFS | 1 Std - 3 Std. | Qualität spielt bei Software eine immer stärkere Rolle. Gleichzeitig werden immer effizientere Entwicklungsprozesse angestrebt. Dies lässt sich nur mit geeigneter Tool-Unterstützung und passenden Lösungen zu Prozessen und Software-Architektur erzielen. Mit Visual Studio Team System und Team Foundation Server stehen Tools zur Verfügung, die nicht nur eine entsprechende Testunterstützung bietet, sondern auch komplette Qualitätsprozesse unterstützt. Der Vortrag zeigt, wie Qualitätsprozesse durch TFS unterstützt werden. Anschließend werden verschiedene Testmethoden vorgestellt und einige Praxis-Tipp für deren Einsatz gegeben. | | Agile Development Process - Ein Architekturbasierter Entwicklungsprozess | 1 Std Vortrag, 1 Std. Demo | Moderne Software-Anwendungen werden immer komplexer. Dadurch gewinnt auch die Software-Architektur immer mehr an Bedeutung. Wartbarkeit, Testbarkeit, Erweiterbarkeit und Teamentwicklung sind nur einige Aspekte, die eine gute Architektur unterstützen soll. Doch diese Aspekte können nicht durch ein einzelnes Architekturkonzept abgedeckt werden. Dieser Vortrag stellt verschiedene Architektur-Patterns wie Komponentenorientierung, Contract First Design, Service-Orientierung und UI Driven Development vor. Und vor allem wird gezeigt, wie diese Konzepte zu einem praxiserprobten Entwicklungsprozess verbunden werden können. | | Mehrschichtige Architekturen mit .Net | 1 Std. | Mehrschichtige Architekturen sind heute eigentlich oft Standard, vor allem bei verteilten Anwendungen. Allerdings wird diese Architektur oftmals zu sehr an technischen Belangen ausgerichtet. Die Session zeigt, wie man mehrschichtige Architekturen plant und diese flexibel und leitungsfähig aufbaut. Es werden verschiedene praxiserprobte Patterns vorgestellt. | | Build-Management mit Team Foundation Server | 1 Std. | Mit Team Foundation Server steht ein leistungsfähiges integriertes Buildsystem zur Verfügung. Wie man dieses im Rahmen der Projekte nutzt und welche Vorteile sich daraus ergeen zeigt diese Session. Darüber hinaus wird der Einsatz verschiedener Buildsteps zum Deployment, Versionierung etc. vorgestellt. | | Testing Practices mit VSTS und TFS | 1 Std. - 3 Std. | VSTS bringt eine ganze Reihe von Testmethoden. Insbesondere die Edition für Tester bietet verschiedene Testarten. Die Implementierung der unterschiedlichen Testarten ist inzwischen hinlänglich beschrieben. Wie diese Tests in Real-World-Projekte eingesetzt werden, um tatsächlich die Qualität zu verbessern, beschreibt der Vortrag ebenso wie die Lösung von Real-World-Problemen. Dabei werden Themen wie die Bereitstellung von Testumgebungen, Testplanung und Testdurchführung sowie Testdokumentation ebenso beleuchtet wie die Frage, in welchen Fällen eine Edition für Tester notwendig ist, wo es mögliche Alternativen gibt und wie verschiedene Akteure innerhalb des Projekts wie z.B. Fachabteilungen eingebunden werden. | | UI-Testing mit UI Automation | 1 Std. - 1,5 Std. | Unit-Testing und Web-Testing verbreiten sich mit VSTS und anderen Testing-Tools immer mehr. Was diese Testmethoden jedoch nicht abdecken, ist quasi die „letzte Meile“, die Oberfläche der Anwendungen. Um diese in Tests einzubinden sind entweder teure Tools erforderlich, oder man nutzt das weitgehend unbekannte UI Automation Framework, das Bestandteil des .NET 3.0 Frameworks ist. Der Vortrag erläutert zunächst, wie man mit Hilfe des UI Automation Frameworks Windows- und WPF-Anwendungen kontrollieren kann. Anschließend werden diese Methoden in Unit-Tests integriert, um damit automatisierte UI-Tests aufzubauen. Als krönender Abschluss wird ein UI-Test-Recorder implementiert, mit dem UI-Aktionen aufgezeichnet und automatisiert in Unit-Test überführt werden können. Der Vortrag beschreibt neben den Möglichkeiten auch Grenzen des UI Automation Frameworks und mögliche Lösungen. | | Closing Tool-Gaps in your Development Process with the TFS API | 1 Std. | The efficiency of development processes is based on a powerful and integrated tool support. But development processes are individual and no standard software can fulfill this integration 100%. With the Team Foundation Server API we have a powerful technology to extend the standard functionality for our needs. As an example in this session we will live code a tool to organize workitems in a hierarchical way and you will learn how this can improve your development process. Also you will get some additional visions about how you can use TFS Extensibility to make real cool things with your TFS. | | Lücken in der Tool-Unterstützung für IhrenEntwicklungsprozess mit der TFS API schließen | 1 Std. | Die Effizienz eines Entwicklungsprozesses hängt stark von einer leistungsfähigen und integrierten Entwicklungsplattform ab. Aber Entwicklungsprozesse sind individuell an keien Standardsoftware kann eine 100%ige Integration gewährleisten. Mit der Team Foundation Server API steht eine leistungsfähige Technologie zur Verfügung, die es erlaubt, die Standard-Funktionen des Team Foundation Servers bedarfsgerecht zu erweitern. Als Beispiel wird in dieser Session ein live ein Tool erstellt, das eine hierarchische Organisation von Workitems ermöglicht. Und es wird erläutert, wie damit Entwicklungsprozesse verbessert werden können. Darüber hinaus werden verschiedene Visionen aufgezeigt wie man mit Hilfe der TFS Extensibility richtig coole Sachen für den TFS machen kann. | | Durchgängige Entwicklungsprozesse mit Visual Studio Team System | 1 Std. | Mit Visual Studio Team System bietet Microsoft eine leistungsfähige Entwicklungsplattform die den gesamten Lebenszyklus eines Entwicklungsprojektes vom Requirement Management bis zum Systembetrieb abbilden kann. Der Vorteil dabei ist, dass alle wichtigen Elemente des Prozesses in einem System integriert und so Verbindungen zwischen den einzelnen Prozessartefakten hergestellt werden können. Der Vortrag zeigt wie ein kompletter Entwicklungsprozess mit VSTS abgebildet werden kann. Als Beispiel wurde hierzu bewusst ein agiler Prozess gewählt der vor allem auch für kleinere Entwicklungsteams geeignet ist. Dabei werden die wesentlichen Funktionselemente von Visual Studio Team System und Team Foundation vorgestellt und deren Nutzung im Prozess gezeigt. | | Reporting mit dem TFS | 1 Std. | Der Team Foundation Server bietet umfangreiche Projekt-Kennzahlen. Neben Prozess- und Qualitätskennzahlen sowie verschiendenen Planungskenngrößen können auch weitere Daten wie z.B. zum Build-Prozess oder aus der Quellcode-Verwaltung ausgewertet werden. Hierbei stehen mit den SQL Server Reporting Services und Excel zwei leistungsfähige Tool zur Verfügung, diese Daten zu visualisieren. Der Vortrag zeigt anhand verschiedenen Beispielen auf, wie individuelle Auswertungen erstellt werden können und welche Möglichkeiten sich damit eröffnen. | | UI Driven Development - Von der UI zur Anwendung | 0,5 Std. - 1 Std. | Missverständnisse und unterschiedliche Interpretation von Spezifikationen sind in Software-Projekten heute an der Tagesordnung. Was also tun, um dieses zu vermeiden? Die Spezifikation noch detaillierter formulieren? Einen anderen Ansatz geht UI Driven Development. Hierbei wird die Oberfläche einer Anwendung als Spezifikationsbestandteil aufgefasst. Der Clou dabei ist, das bei diesem Vorgehensmodell nicht irgendwelche Prototypen entstehen, die die spätere Funktionalität und Aufbau nur vage wiedergeben, sondern "erlebbare" Oberflächen. Und diese Oberflächen können in das Finale Projekt 1:1 übernommen werden, so dass der Investierte Aufwand direkt dem Projekt zugute kommt. Der Vortrag erläutert Architekturkonzepte und Vorgehensmodelle die UI Driven development ermöglichen. | | Organisation von Entwickler-Teams | 0,5 Std. - 1,5 Std. | Dieser Vortrag ist als Interactive Session konzipiert. Die Teilnehmer können in einer moderierten Diskussionsrunde sich austauschen über verschiedene Erfahrungen mit unterschiedlichen Modellen der Team-Organisation. Der Moderator stellt dabei im Laufe der Veranstaltung verschiedene Aspekte der Team-Organisation und mögliche Vorgehensweisen vor und stellt diese zur Diskussion. Dabei werden Themen wie Generalisten vs Spezialisten, Kommunikation im Team, Mitarbeitermotivation und vieles mehr ausführlich diskutiert. | | Automatisierte Generierung von Unit-Tests mit PEX | 0,5 Std. | PEX - ein Tool von Microsoft Research verspricht nichts weniger als die automatisierte Generierung von Unit-Tests und zwar mit dem Ziel einer möglichst vollständigen Code-Abdeckung. Wie PEX funktioniert und inwieweit dieses Versprechen eingehalten werden kann, zeigt dieser Vortrag. Darüber hinaus wird auch beleuchtet, in welchen Szenarien PEX eine wirklich sinnvolle Unterstützung bei Real-Projekten sein kann und wie man es einsetzen kann. | | 10 Gründe warum Software-Projekte fehlschlagen können – und was hilft ALM? | 1 Std. | Für Probleme in Software-Projekten gibt es vielfältige Gründe. Viele dieser Gründe können jedoch auf suboptimale oder gar nicht vorhandene Prozesse zurückgeführt werden. Der Vortrag analysiert die häufigsten Ursachen für fehlgeschlagene Projekte und zeigt mögliche Lösungen auf. Dabei wird auch beleuchtet wie Application Lifecycle Management organisiert sein muss um hier zu unterstützen. | | TDD Quick Start | 0,5 Std. | Test Driven Development - Eines der häufigsten Buzz-Wörter wenn es um das Thema Software-Testing geht. Umso erstaunlicher, dass es in der Praxis aber relativ selten zum Einsatz kommt. Häufig liegt es auch daran, dass TDD an gewisse Vorbedingungen in Bezug auf Architektur, Prozesse etc. gebunden ist. Der Vortrag versucht einen Schnelleinstieg in TDD zu geben, wobei versucht wird diese Vorbedingungen weitgehend auszublenden um dem Zuhörer einen möglichst schnellen und unkomplizierten Einstieg zu bieten. Die hierzu erforderlichen Kompromisse werden jedoch am Ende des Vortrages aufgezeigt und ein Ausblick auf optimierte Lösungen gegeben. |
Wo finde ich eine User-Group in meiner Nähe? Diese Frage beantwortet der Usergroup-Kompass. Eine wirglich schöne Idee wie ich finde. User Group-Kompass
In der vergangenen Woche war ich bei gleich 3 User-Groups in Bonn, Stuttgart und bei uns in Ulm und habe dort meinen Vortrag zu architekturbasierten Entwicklungsprozessen gehalten. Dabei ging es im Kern darum, dass moderne Software.Projekte bestimmte Anforderungen an Prozesse haben. Der Vortrag zeigte hier zunächst verschiedene dieser Anforderungen an Testbarkeit, Team-Arbeit und die Definition von Spezifikationen. Anschließend wurden verschiedene Architekturkonzepte vorgestellt um dann aufzuzeigen, wie diese Konzepte die Prozessanforderungen erfüllen können. Zum Abschluss wurde dann das Ganze mit einem Demo-Projekt anschaulicher dargestellt. Die Folien und das Demo kann hier heruntergeladen werden:
 Das patterns & practices Team hat einen Application Architect Guide veröffentlicht. Das 365 Seiten umfassende Dokument kann kostenlos von CodePlex heruntergeladen werden und beschreibt Architekturansätze für Windows, Web, Mobile und andere Anwendungen. Neben theoretischen Grundlagen werden auch explizite Guidelines für verschiedene Design-Aspekte einer Anwendung beschrieben. Absolut empfehlenswert! patterns & practices: Application Architecture Guide 2.0 (The Book) - Home
 Gestern Abend habe ich bei der .Net Developer Group Braunschweig einen Vortrag zu Agile Development Process - Ein architekturbasierter Entwicklungsprozess gehalten. Während des Vortrages und vor allem am Ende gab es eine sehr gute und interessante Diskussion. Bei dem Vortrag habe ich demonstriert wie wir bei uns im Unternehmen verschiedene Architekturpatterns verwenden um Prozessanforderungen zu unterstützen. Dabei kommen bewährte Konzepte wie Komponentenorientierung, Contract First und mehrschichtige Architektur zum Einsatz, aber auch von uns angepasste bzw. neu entwickelte Methoden. Die Folien und das Demo kann hier heruntergeladen werden:
Der Team Foundation Server verwendet in den Versionen bis 2008 eine XML-Datei um den Build-Prozess zu steuern. Diese Datei wird Build Project File genannt und wird in der Versionsverwaltung abgelegt um vom Buildcomputer genutzt werden zu können. Jeder der diese Datei aber schon manuell bearbeitet hat, kennt das umständliche Vorgehen umd die Date erst aus der Quellcode-Verwaltung auszuchecken, und nach dem Bearbeiten wieder einzuchecken. Einfacher geht das mit den TFS Sidekicks, die direkt im Context-Menü des Team-Explorers eine Checkout und Checkin-Funktion für das Project-File anbietet. Darüber hinaus bieten die TFS Sidekicks noch weitere sehr nützliche Funktionen, auf jeden Fall ist das Tool einen näheren Blick wert. Attrice Corporation - Team Foundation Sidekicks
Today I had my second talk on the TechEd in Barcelona. It was about closing tool gaps in development processes and using the TFS API. Thanks to all attendees joined my session. We had some very interesting discussion at the end, and I got a lot of positive feedback like “This was what I was looking for”. For all here comes the promised downloads for the slides and demos. Feel free to use them in either way. And here the link to download WorkitemManager. At www.alm-tools.com you can download the Open version which is free and also the source code. And if you are interested in one of the tools I showed, please just send me an e-Mail to tschissler (at) artiso (.) com.
Ok, not to confuse you, I'm not going to blog English from now on. But I did a session on UI-Testsing with the UI Automation Framework and to provide slides and demo-code to the attendees I use this blog post. The session went fairly well from my point of view and I had some really interesting discussions on this topic after the session. I hope those who have joined me got some good information about how you can do UI-testing today with completely free tools. I'll provide some pictures later because I cannot read them from my camera right now. Here comes the downloads:
Mit ein wenig Verspätung wurden die TFS Power Tools October 2008 nun released. Dafür wurden aber noch ein paar wichtige Bugs gefixed. Damit stehen nun die größten Power-Tools zur verfügung, die jemals veröffentlicht wurden. Über die Features habe ich bereits hier gebloggt. ich denke damit werden ein paar wichtige Lücken geschlossen und durch die Explorer Integration wird TFS für weitere Szenarien interessant. Download details: Team Foundation Power Tools
Der artiso Workitem Manager ist ein Tool mit dem sich Workitems hierarchisch organisieren lassen. Diese hierarchische Organisation bietet verschiedene Vorteile. Neben einer besseren Strukturierung und einer erhöhten Übersichtlichkeit vor allem auch eine visuelle Traceability. Damit ist gemein, dass durch die Hierarchie sichtbar wird welche Tests und Implementierungsaufgaben einem Feature zugeordnet sind. Die ist z.B. sehr hilfreich, wenn sich das Feature ändert zu erkennen, welche Workitems auf mögliche Auswirkungen überprüft werden können. Wie hierarchische Workitems in Projekten hilfreich eingesetzt werden, habe ich zusammen mit Christian Binder in diesem MSDN-Webcast erörtert. Leider bringt der TFS in der Version 2008 diese Hierarchie nicht von Haus aus mit. Deshalb hat artiso den Workitem Manager entwickelt. Diesen gibt es nun auch als Open-Version. Die Open-Version ist kostenlos und wird auch als Source-Code bereitgestellt. Wie sich der Workitem Manager Open zur Vollversion unterscheidet kann man der unten stehenden Funktionsmatrix entnehmen. Weiter unten gibt's noch eine Screenshot. Den Donload für das Setup und den Source-Code findet man unter http://www.alm-tools.de. Gerne freue ich mich über euer Feedback zu dem Tool.  
Seit kurzem bin ich stolzer Besitzer einer Microsoft Wireless Notebook Presenter Mouse 8000 (was für ein Name!). Auf meinem Notebook hatte ich aber ständig das Problem dass die Meldung "HDI data has stopped working" kam. Zwar funktionierte das System ohne Probleme aber die Meldung war extrem nervig, vor allem bei Demos und Vorträgen. Nach einigem suchen bin ich dann auf einen Forum-Thread gestossen der genau für dieses Problem eine Lösung beschreibt. Der entscheidende Post hier nochmals kurz zitiert: I was having the same problem with my bluetooth microsoft wireless notebook presenter mouse 8000. The problem is created by an application in the HP quick launch Buttons. I removed the application from the launch buttons.
go to:
C:\Program Files\Hewlett-Packard\HP Quick Launch Buttons
move the following files to a backup folder on your computer:
HidActn.dll Hiddata PushHid.dll
Then restart you computer and you should not have the errors and the other things on your laptop should still be available. "HID data has stopped working" - bluetooth mouse error - Vista Hardware Devices
Wie ich hier bereits gepostet habe, verschmilzt Microsoft die Visual Studio Team System Development Edition mit der Database Edition, aus meiner Sicht eine wirklich gute Lösung. Um dieses Thema treten aber immer wieder Fragen auf, so dass ich hier mal die wichtigsten gesammelt habe und natürlich auch beantworte. F: Wie installiere ich die zusätzliche Edition? A: Auf MSDN steht den Abonenten die jeweils andere Edition nun zusätzlich zum Download zur Verfügung. Diese kann hier heruntergeladen und dann einfach zusätzlich zur bestehenden Installation installiert werden. Die zusätzlichen Funktionen integrieren sich dann in die bestehende Installation. Ein gemeinsames Installationspaket ist momentan nicht geplant. Mit VS2010 werden die beiden Editionen dann als gemeinsames Paket ausgeliefert. F: Für welche Editionen gilt diese Option? A: Die Option gilt sowohl für die 2005er als auch für die 2008er Editionen, im Detail also für: Visual Studio 2005 Team Edition for Software Developers with MSDN Premium Subscription Visual Studio 2005 Team Edition for Database Professionals with MSDN Premium Subscription Visual Studio Team System 2008 Development Edition with MSDN Premium Subscription Visual Studio Team System 2008 Database Edition with MSDN Premium Subscription
F: Wie verhält sich das mit Servicepacks? A: Nach der Installation der zusätzlichen Edition müssen die Servicepacks erneut installiert werden. Weitere Informationen finden sich auch auf der FAQ-Seite zum Merge. FAQ - MSDN Subscribers with Visual Studio Team System Development Edition or Database Edition
Das neueste CTP zu Visual Studio 2010 (Codename Rosario) steht nun zum Download bereit. Das CTP wird als VPC Image bereitgestellt. Mit Visual Studio 2010 kommen viele neue interessante Features. Vor allem im Bereich Testing und Architektur hat sich hier vieles getan. Ich werde mit diesem CTP beginnen, die einzelnen Funktionen näher zu beleuchten und sicher in nächster Zeit den einen oder andern Blogbeitrag zu diesem Thema schreiben. Es gibt mit dem CTP verschiedene Aktivierungs-Meldungen. Diese können jedoch meistens einfach ignoriert werden, das Image läuft ganz normal weiter. Download details: Visual Studio 2010 and .NET Framework 4.0 CTP
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!
Was bedeutet was? Christian Binder's Weblog : Alle Visual Studio Teamsystem Session auf dem Technical Summit 2008 im Überblick
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.
Im folgenden Dialog können Sie verschiedene Parameter angeben. Das wichtigste hier ist das Testprojekt in dem der Stub erzeugt werden soll.
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.
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.
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.
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.
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?
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.
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.
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.
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.
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: { 9: if (i > 100) 10: i = 100; 11: List<int> l = new List<int>(); 12: for (int j = 0; j < i; j++) 13: { 14: l.Add(j * 10); 15: } 16: return l; 17: } 18: } 19: }
Hier teilt man PEX nun mit, welche Elemente es damit erzeugen kann (Zeile 6). Anschließend implementiert man eine Create-Methode die beliebige Parameter übernehmen kann. In Abhängigkeit dieser Parameter wird nun eine Instanz des gewünschten Objektes erzeugt. In unserem Beispiel übernehmen wir nur einen Parameter der die Länge der Liste angibt. In den Zeilen 9/10 begrenzen wir die Länge der Lsite auf 100 Elemente. Die Liste selbst befüllen wir mit einer Reihe von Zahlen. Hier ist es sicher keine gute Idee, z.B. Zufallszahlen zu verwenden, da diese ja bei jedem Testdurchlauf andere Werte liefern und deshalb der Assert nicht erfolgreich ausgeführt werden kann.
Mit hilfe dieser Factory kannPEX nun unsere Testcases definieren. Dazu ermittelt es einfach geeignete Parameter für die Create-Methode in unserer Factory statt das Objekt selbst zu erzeugen.
Die erzeugten Tests sehen dann so aus:
1: [TestMethod] 2: [PexGeneratedBy(typeof(ListCalculationTest))] 3: public void SumList03() 4: { 5: List<int> list; 6: int i; 7: list = ListFactory.Create(2); 8: ListCalculation listCalculation = new ListCalculation(); 9: i = this.SumList(listCalculation, list); 10: Assert.AreEqual<int>(0, i); 11: } 12: 13: [TestMethod] 14: [PexGeneratedBy(typeof(ListCalculationTest))] 15: public void SumList04() 16: { 17: List<int> list; 18: int i; 19: list = ListFactory.Create(536870912); 20: ListCalculation listCalculation = new ListCalculation(); 21: i = this.SumList(listCalculation, list); 22: Assert.AreEqual<int>(49500, i); 23: }
Nun folgt noch die Kür
Nach den Erfahrungen mit der Liste bereits etwas skeptischer geworden, wollen wir's jetzt aber doch wissen. Wie sieht's mit eigenen Objekten aus? Wie weit kommt PEX damit? Auch hier gibt es wieder eine einfache Methode die wir testen wollen:
1: public class ComplexDataCalculation 2: { 3: public string DoComplexDataCalculation(cData d) 4: { 5: if (!d.IsValid) 6: return "NotValid"; 7: 8: if (d.DataValues.x1 > d.DataValues.x2) 9: return "x1 > x2"; 10: if (d.DataValues.x1 < d.DataValues.x2) 11: return "x1 < x2"; 12: else 13: return "x1 == x2"; 14: 15: } 16: } 17: 18: public class cData 19: { 20: public cDataValues DataValues { get; set; } 21: public string ObsoleteParameter { get; set; } 22: public bool IsValid { get; set; } 23: } 24: 25: public class cDataValues 26: { 27: public int x1 { get; set; } 28: public int x2 { get; set; } 29: }
Die Methode bekommt einen komplexen Datentyp übergeben. Und was macht PEX???
PEX erkennt nicht nur, dass wir zwei Null-Exceptions abfangen sollten, sondern kann auch unser Datenobjekt so initialisieren, dass wir wieder eine 100% Codeabdeckung bekommen. Die Unit-Tests sehen ungefähr so aus:
1: [TestMethod] 2: [PexGeneratedBy(typeof(ComplexDataCalculationTest))] 3: public void DoComplexDataCalculation04() 4: { 5: cDataValues cDataValues; 6: cData cData; 7: string s; 8: cDataValues = new cDataValues(); 9: cDataValues.x1 = 3; 10: cDataValues.x2 = 4; 11: cData = new cData(); 12: cData.DataValues = cDataValues; 13: cData.ObsoleteParameter = ""; 14: cData.IsValid = true; 15: ComplexDataCalculation complexDataCalculation = new ComplexDataCalculation(); 16: s = this.DoComplexDataCalculation(complexDataCalculation, cData); 17: Assert.AreEqual<string>("x1 < x2", s); 18: }
Das ist schon extrem beeindruckend, wie PEX tatsächlich eine entsprechende Instanz unseres Datenobjektes erzeugt und initialisiert und das so, dass wir alle Testcases abdecken. Wirklich beeindruckend.
Was haltet ihr davon? Würde mich über Feedback freuen.
Die Integration des TFS mit Visual Studio ist eine richtig schöne Sache. Eine Stelle an der die Vorteile dieser Integration schön sichtbar werden ist die Erzeugung einen Workitems direkt aus einem Test-Result heraus. Wenn also z.B. ein Test fehlgeschlagen ist, kann daraus direkt ein Bug-Workitem erzeugt werden. Der Clou dabei ist, dass das Test-Result automatisch auf dem TFS veröffentlicht und als Attachment an das Workitem angehängt wird. Damit hat der Entwickler der den Bug beheben soll Zugriff auf den durchgeführten Test und die Results. Dies funktioniert mit allen Testarten sofern der Entwickler mit seiner Visual Studio Edition die entsprechenden Testarten ausführen kann. Somit kann der Entwickler z.B. bei einem Unit-Test diesen verwenden um den Testcase einfach zu debuggen. Und bei manuellen Tests stellt die Testspezifikation die Beschreibung der Repro-Steps dar. Auf jeden Fall ein Zeitgewinn. Man kann aber beispielsweise damit auch Aufgaben definieren, dass ein bestimmter Test noch mit zusätzlichen Test-Cases angereichert werden soll etc. Dazu geht man einfach mit der rechten Maustaste auf den entsprechenden Eintrag im Testresults-Fenster und wählt aus dem Kontext-Menü den entsprechenden Workitemtyp aus. Wird statt der Liste der Workitems "No Active Team Project" angezeigt, dann gibt es hier eine einfache Lösung, die aber nicht ganz intuitiv ist. 1.) Sicherstellen dass im Team-Explorer das gewünschte Projekt angezeigt wird in dem man das neue Workitem anlegen möchte. 2.) Dieses Team-Projekt aktiv markieren (das Projekt wird fett dargestellt) Nun werden die WorkitemTypen die im ProcessTemplate dieses Projektes definiert sind zur Auswahl angezeigt. Das Projekt selbst muss nicht unbedingt in der Quellcode-Verwaltung des TFS abgelegt sein.
 Nächste Woche Dienstag bin ich mit zwei Vorträgen auf der ADC08 vertreten. Testing Practices mit VSTS und TFS VSTS bringt eine ganze Reihe von Testmethoden. Insbesondere die Edition für Tester bietet verschiedene Testarten. Die Implementierung der unterschiedlichen Testarten ist inzwischen hinlänglich beschrieben. Wie diese Tests in Real-World-Projekte eingesetzt werden, um tatsächlich die Qualität zu verbessern, beschreibt der Vortrag ebenso wie die Lösung von Real-World-Problemen. Dabei werden Themen wie die Bereitstellung von Testumgebungen, Testplanung und Testdurchführung sowie Testdokumentation ebenso beleuchtet wie die Frage, in welchen Fällen eine Edition für Tester notwendig ist, wo es mögliche Alternativen gibt und wie verschiedene Akteure innerhalb des Projekts wie z.B. Fachabteilungen eingebunden werden. UI-Testing mit UI Automation Unit-Testing und Web-Testing verbreiten sich mit VSTS und anderen Testing-Tools immer mehr. Was diese Testmethoden jedoch nicht abdecken, ist quasi die „letzte Meile“, die Oberfläche der Anwendungen. Um diese in Tests einzubinden sind entweder teure Tools erforderlich, oder man nutzt das weitgehend unbekannte UI Automation Framework, das Bestandteil des .NET 3.0 Frameworks ist. Der Vortrag erläutert zunächst, wie man mit Hilfe des UI Automation Frameworks Windows- und Web-Anwendungen kontrollieren kann. Anschließend werden diese Methoden in Unit-Tests integriert, um damit automatisierte UI-Tests aufzubauen. Als krönender Abschluss wird ein UI-Test-Rekorder implementiert, mit dem UI-Aktionen aufgezeichnet und automatisiert in Unit-Test überführt werden können. Der Vortrag beschreibt neben den Möglichkeiten auch Grenzen des UI Automation Frameworks und mögliche Lösungen.
 Seit ein paar Tagen ist ein neuer Web-Cast online in dem ich zusammen mit Christian Binder zusammen erörtere welche Vorteile die hierarchische Organisation von Workitems bietet. Ohne schon zuviel vom Inhalt verraten zu wolle, es geht um Requirementmanagement, Traceability, Impace-Analyse und einiges mehr. Im Webcast wird ein kostenloses Tool vorgestellt mit dem bereits mit TFS 2008 hierarchische Workitems realisiert werden können.
Mit Hilfe des UI Automation Frameworks (UIA) können Oberflächen aus einer Testanwendung heraus "ferngesteuert" werden. Damit lassen sich z.B. UI-Tests bauen. Die Grundlagen hierzu habe ich in zwei Blogposts bzw. Webcasts beschrieben. MSDN WebCast zum UI-Recording MSDN WebCast zum UI-Testing mit dem UI Automation Framework Wenn man sich mit dieser Technologie etwas intensiver beschäftigt wird man früher oder später auf ein paar Probleme stoßen. So veröffentlichen beispielsweise nicht alle Third-Party-Controls alle erforderlichen Funktionalitäten über die UIAutomation Patterns. Und leider gibt es auch bei Standard-Winforms-Controls noch ein paar Lücken. Ein Beispiel hierzu ist das MenuStrip-Control. Dieses Control bietet leider nicht die erforderlichen Events um die Auswahl eines Menüeintrags aufzuzeichnen. Und für die Auswahl eines Menüeintrages gibt es auch kein geeignetes Invoke-Pattern o.ä. Das schöne am UI Automation Framework ist jedoch, dass man diese Funktionalitäten selber nachrüsten kann. Dies wollen wir nun am Beispiel des MenuStrips mal durchspielen. Zum Einsatz kommen sog. Serverside Provider. Wir gehen zunächst her und erstellen uns ein eigenes Control das wir von MenuStrip und entsprechenden Interfaces aus dem UIA ableiten. public class ExtendedMenuStrip : MenuStrip, IRawElementProviderSimple, IValueProvider
Über das Interface IValueProvider geben wir an, dass das Control das ValuePattern implementieren soll. Wir verwenden hier das ValuePattern statt des InvokePatterns da wir ja angeben müssen, welches Menüelement aufgerufen werden soll.
Zunächst werden wir das Interface IRawElementProviderSimple implementieren.
1: #region IRawElementProviderSimple Members 2: public object GetPatternProvider(int patternId) 3: { 4: if (patternId == ValuePatternIdentifiers.Pattern.Id) 5: { 6: return this; 7: } 8: else 9: { 10: return null; 11: } 12: } 13: 14: /// <summary> 15: /// Get the value of properties 16: /// </summary> 17: /// <param name="propertyId"></param> 18: /// <returns></returns> 19: public object GetPropertyValue(int propertyId) 20: { 21: if (propertyId == AutomationElementIdentifiers.ClassNameProperty.Id) 22: { 23: return "ExtendedMenuStrip"; 24: } 25: else if (propertyId == AutomationElementIdentifiers.ControlTypeProperty.Id) 26: { 27: return ControlType.MenuBar.Id; 28: } 29: 30: if (propertyId == AutomationElementIdentifiers.HelpTextProperty.Id) 31: { 32: return "Help for ExtendedMenuStrip"; 33: } 34: 35: if (propertyId == AutomationElementIdentifiers.AutomationIdProperty.Id) 36: { 37: return this.Name; 38: } 39: 40: if (propertyId == AutomationElementIdentifiers.IsEnabledProperty.Id) 41: { 42: return true; 43: } 44: 45: if (propertyId == AutomationElementIdentifiers.ItemStatusProperty.Id) 46: { 47: return SelectedItemID; 48: } 49: 50: else 51: { 52: return null; 53: } 54: } 55: 56: /// <summary> 57: /// Get the host rawelement provider 58: /// </summary> 59: public IRawElementProviderSimple HostRawElementProvider 60: { 61: get 62: { 63: return AutomationInteropProvider.HostProviderFromHandle(Handle); 64: } 65: } 66: 67: /// <summary> 68: /// Get the provider options 69: /// </summary> 70: public ProviderOptions ProviderOptions 71: { 72: get 73: { 74: return ProviderOptions.ServerSideProvider; 75: } 76: } 77: 78: #endregion
Die Methode GetPatternProvider gibt das Objekt selbst zurück, wenn ein Provider für ein ValuePattern angefordert wird. Da unser Control nur dieses Pattern implementiert, reagiert die Funktion nur auf dieses Pattern. Wir können das Control selbst zurückgeben, da dieses ja das ValuePattern implementiert. Altzernativ könnte man natürlich auch einen expliziten Provider definieren und hier zurückgeben. Die Methode GetPropertyValue gibt je nach übergebenen PropertyID einen entsprechenden Wert zurück. Hier wird z.B. die ID des Controls als AutomationID zurückgegeben. Die beiden Properties HostRawElementProvider und ProviderOptions sind readonly und geben einen Hostprovider bzw. den Typ der Providers zurück.
Die Implementierung des IValueProvider Interface ist ebenfalls recht einfach:
1: #region IValueProvider Members 2: /// <summary> 3: /// Get readonly as false 4: /// </summary> 5: public bool IsReadOnly 6: { 7: get 8: { 9: return false; 10: } 11: } 12: 13: /// <summary> 14: /// Set value: Invoke the click event of the item 15: /// </summary> 16: /// <param name="value"></param> 17: public void SetValue(string value) 18: { 19: object[] param = new object[1]; 20: param[0] = null; 21: ToolStripMenuItem toolStripMenuItem = getToolStripMenuItemByName(this.Items, value); 22: if (toolStripMenuItem != null) 23: toolStripMenuItem.GetType().GetMethod("OnClick", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(toolStripMenuItem, param); 24: } 25: 26: /// <summary> 27: /// Get the ID of the selected item 28: /// </summary> 29: public string Value 30: { 31: get 32: { 33: return SelectedItemID; 34: } 35: } 36: #endregion
Entscheidend ist hier die Methode SetValue. Hier ermitteln wir das entsprechende Element innerhalb des MenuStrips (ToolStripMenuItem) und rufen hier einen Click-Event auf. Da die OnClick Methode nicht public ist, müssen wir hier Reflection verwenden um diese aufrufen zu können (siehe auch Events von WinForms Controls von Außen aufrufen). Das Aufrufen des Events ist an dieser Stelle notwendig, da ja mehrere Eventhandler registriert sein können und die wollen wir alle aufrufen. Durch den Click-Event verhält sich das Control am ähnlichsten zum Anklicken in der UI.
Nun brauchen wir noch einen Event der ausgelöst wird wenn ein Menüeintrag ausgewählt wird.
1: /// <summary> 2: /// Set eventhandlers 3: /// </summary> 4: /// <param name="items"></param> 5: public void SetExtendedMenuStripEventHandlers(ToolStripItemCollection items) 6: { 7: for (int i = 0; i <= items.Count - 1; i++) 8: { 9: ToolStripMenuItem toolStripMenuItem = items[i] as ToolStripMenuItem; 10: if(toolStripMenuItem != null) 11: { 12: toolStripMenuItem.Click += new EventHandler(ItemRaiseAutomationEvent); 13: SetExtendedMenuStripEventHandlers(toolStripMenuItem.DropDownItems); 14: } 15: } 16: } 17: 18: /// <summary> 19: /// Raise automation event 20: /// </summary> 21: /// <param name="sender"></param> 22: /// <param name="e"></param> 23: private void ItemRaiseAutomationEvent(object sender, EventArgs e) 24: { 25: if ((AutomationInteropProvider.ClientsAreListening)) 26: { 27: AutomationEventArgs args = new AutomationEventArgs(InvokePatternIdentifiers.InvokedEvent); 28: this.SelectedItemID =((ToolStripMenuItem)sender).Name; 29: AutomationInteropProvider.RaiseAutomationEvent(InvokePatternIdentifiers.InvokedEvent, this, args); 30: } 31: }
Die Methode SetExtendedMenuStripEventHandlers registriert auf jedem ToolStripMenuItem einen EventHandler. Dieser löst dann den AutomationEvent aus. Hier übergeben wir im Feld SelectedItemID den Name des ToolStripMenuItems das angeklickt wurde.
Nun müssen wir noch die Methode wndProc überschreiben damit diese bei WM_GETOBJECT den entsprechenden AutomationProvider zurückgibt.
1: /// <summary> 2: /// Process Windows-based messages 3: /// </summary> 4: /// <param name="m"></param> 5: [PermissionSetAttribute(SecurityAction.Demand, Unrestricted = true)] 6: protected override void WndProc(ref Message m) 7: { 8: // 0x3D == WM_GETOBJECT 9: Int32 param = 0; 10: if (Int32.TryParse(m.LParam.ToString(), out param)) 11: { 12: if ((m.Msg == 0x3D) && (param == AutomationInteropProvider.RootObjectId)) 13: { 14: m.Result = AutomationInteropProvider.ReturnRawElementProvider( 15: Handle, m.WParam, m.LParam, (IRawElementProviderSimple)this); 16: return; 17: } 18: } 19: base.WndProc(ref m); 20: }
Das so erstellte Control kann nun statt des normalen MenuStrip Controls verwendet werden und ist nun über UI Automation ansprechbar. Die fertige Solution inkl. dem UI-Recoder kann hier heruntergeladen werden:
Vielleicht noch kurz eine Anmerkung weshalb der Zugriff auf die ToolStripItems etwas umständlich gelöst wurde. Eigentlich wäre es doch einfach der direkt auf dem ToolStripMenuItem den Event auszulösen. Dann könnte der Recoder auch direkt einen Invoke auf dem ToolStripMenuItem generieren. Dazu müsste dann aber der ToolStripMenuItem abgeleitet werden und dann wird's aber mit der Designer-Unterstützung problematisch. Denn um das Control soweit umzubauen, dass im Designer beim Hinzufügen von ToolStripMenuItems zum MenuStrip der abgeleitete Typ verwendet wird ist ein deutlich höherer Aufwand notwendig als das Ganze über den MenuStrip laufen zu lassen.
 Das MSBuild Extension Pack bietet eine Sammlung von BuildTasks für MSBuild und damit natürlich auch TeamBuild die kostenlos von CodePlex heruntergeladen werden können. Diese BuildTasks bieten verschiedene Operationen im Rahmen eines Builds wie z.B. das Zippen und Vermailen von Dateien, Prüfen des Buildprojektes mit FxCop oder StyleCop, verschiedene Dateioperationen und vieles mehr. Die Bibliothek ist gut strukturirert und dokumentiert. MSBuild Extension Pack - Home
Möchte man einen Event eines Controls per Code auslösen und somit alle registrierten Delegates aufrufen, wie es beim eigentlichen Auslösen des Events passiert, dann kann dieses Beispiel helfen. Jedes Control besitzt für seine einzelnen Events eine Methode den event auszulösen, z.B. OnClick(EventArgs e). Die Methoden sind allerdings private und können damit von außerhalb des Controls nicht so einfach aufgerufen werden. Bei einem einfachen Control wie z.B. einem Button geht das einfach durch Ableitung: 1: public partial class CustomButton : Button 2: { 3: public CustomButton() 4: { 5: InitializeComponent(); 6: } 7: 8: public void RaiseClickEvent(EventArgs e) 9: { 10: base.OnClick(e); 11: } 12: }
Etwas schwieriger wird es bei komplexeren Controls, z.B. einem MenuStrip. Möchte man den Click-Event eines ToolStripMenuItem aufrufen, müsste man ja das ToolStripMenuItem ableiten, was aber zur Folge hätte, dass das komplette MenuStrip-Control umbauen muss. Hier kann man mit Hilfe von Reflection eine bessere Lösung implementieren. Bei dieser Lösung wird nur das MenuStrip abgeleitet und um eine RaiseClickEvent-Methode erweitert der als Parameter ein ToolStripItem entgegen nimmt. Auf diesem wird dann per Reflection die Private-Methode OnClick aufgerufen.
1: public partial class CustomMenuStrip : MenuStrip 2: { 3: public CustomMenuStrip() 4: { 5: } 6: 7: public void RaiseClickEvent(ToolStripItem m) 8: { 9: Type t = m.GetType(); 10: object[] para = new object[1]; 11: para[0] = null; 12: t.GetMethod("OnClick", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(m, para); 13: } 14: }
Ich hatte gerade das Problem, dass in einem Feld in der Datenbank Einträge wie z.B. "Thomas, Schissler" standen und ich die in "Schissler, Thomas" ändern wollte. Hier hilft folgendes kleines Skript: select CASE LEN(ResponsibleName)
WHEN 0 THEN ResponsibleName
ELSE SUBSTRING(ResponsibleName, charindex ( ',', ResponsibleName )+2, len(ResponsibleName))
+ ', '
+ SUBSTRING(ResponsibleName, 1, charindex ( ',', ResponsibleName )-1)
END
from data
In einem früheren Beitrag habe ich beschrieben, wie man kleinere Listen mit LINQ effizien speichern kann. Hierzu verwende ich einfach ein XML-Feld in der entsprechenden Tabelle und lege die Liste dann dort als XML-Serialisierung ab. Nun stand ich vor der Herausforderung, dass ich direkt auf der Datenbank dieses Feld abfragen wollte. Glücklicherweise beitet T-SQL eine sehr gute XML-Unterstützung, unglücklicherweise gibt es eine vielzahl von Techniken dies zu tun und die Treffer meiner Internetrecherche waren sehr unübersichtlich. Deshalb hier nochmals kurz zusammengefasst, wie ich das gelöst habe. Ich habe in einem Feld folgenden XML-Inhalt der ein Dictionary mit 5 Einträgen repräsentiert: <Root>
<item>
<key>
<int>1</int>
</key>
<value>
<decimal>17.00</decimal>
</value>
</item>
<item>
<key>
<int>2</int>
</key>
<value>
<decimal>17.81</decimal>
</value>
</item>
<item>
<key>
<int>3</int>
</key>
<value>
<decimal>18.62</decimal>
</value>
</item>
<item>
<key>
<int>4</int>
</key>
<value>
<decimal>19.43</decimal>
</value>
</item>
<item>
<key>
<int>5</int>
</key>
<value>
<decimal>20.24</decimal>
</value>
</item>
</Root>
Die Struktur der XML-Daten ist bei allen Datensätzen gleich. Nun wollte ich diese Werte in 5 separaten Spalten ausgeben um diese einfachin Excel weiterverarbeiten zu können. Das macht folgendes Skript:
SELECT PackSIzeID, Units,
u1.l.value('decimal[1]','Decimal(18,2)') AS UnitsYear1,
u1.l.value('decimal[1]','Decimal(18,2)') AS UnitsYear2,
u1.l.value('decimal[1]','Decimal(18,2)') AS UnitsYear3,
u1.l.value('decimal[1]','Decimal(18,2)') AS UnitsYear4,
u1.l.value('decimal[1]','Decimal(18,2)') AS UnitsYear5
FROM data_PackSizes
CROSS APPLY Units.nodes('//Root/item[1]/value') u1(l)
CROSS APPLY Units.nodes('//Root/item[2]/value') u2(l)
CROSS APPLY Units.nodes('//Root/item[3]/value') u3(l)
CROSS APPLY Units.nodes('//Root/item[4]/value') u4(l)
CROSS APPLY Units.nodes('//Root/item[5]/value') u5(l)
Hier kann ich die 5 values als separate Nodes adressieren und dann in der Feldliste entsprechend auswählen. Das Ergebnis sieht dann so aus:
Vielleicht geht das auch noch eleganter, aber für mich hat's erst mal funktioniert und deshalb habe ich hier erst mal nicht mehr Zeit investiert.
Weitere Infos zum Thema: SQL XML-Workshop von Jacob Sebastian
Technet-Whitepapaer: XML Best Practices for Microsoft SQL Server 2005
Die nächste Version der TFS Power-Tools werden ein paar richtig coole Features enthalten sein. Z.B. ein neuer Knoten "Team Members" im Team Explorer über den man mit allen Team-Mitglieder kommunizieren kann und worüber man auch z.B. schnell die Pending Changes oder die Shelfsets einzelner Mitglieder findet etc.   Zusätzlich lassen sich damit Komponenten wie z.B. Checkin-Policies oder Workitem-Controls einfach distributieren.  Und von vielen heiß ersehnt, es gibt jetzt eine Windows Explorer Integration zur Quellcode-verwaltung.   Darüber hinaus ist noch der Power-Shell Support Bestandteil der neuen Power-Tools Weitere Details unter Brian Harrys Blog bharry's WebLog : Preview of the next TFS Power Tools release
 Ok, OK, ich weiß, ich bin spät dran, aber ich möchte dennoch nicht versäumen, einen kurzen Rückblick auf den Herbstcampus zu tun und meine Folien zu veröffentlichen. Interessant war für mich an der Veranstaltung, dass es Tracks sowohl für JAVA als auch .Net gab. Ich selbst hatte zwei Talks: Qualitätsmanagement mit VSTS und TFS In dieser Session habe ich zunächst einmal beleuchtet, warum Entwickler QM nicht unbedingt mögen. Einer der Gründe liegt in der mangelnden Integration von QM in den Entwicklungsprozess. Gerade hier bietet VSTS und TFS einige Verbesserungen. Wichtig ist, dass QM nicht erst mit dem Testing beginnt, sondern bereits früh im Prozess ansetzen muss. Ohne ein gutes Requirement-Management wird kein gutes Qualitäts-Management möglich sein. Im Vortrag habe ich demonstriert, welche Methoden mit diesem Toolset über die verschiedenen Prozessphasen zur Verfügung stehen um in Software-Projekten wirklich mehr Qualität zu erzielen. Agile Development Process - Ein Architektur-basierter Entwicklungsprozess Architektur und Prozesse werden meist getrennt betrachtet. Dass aber gerade eine gemeinsame Betrachtung dieser beiden Themen viele Vorteile bringt, habe ich versucht in dieser Session zu vermitteln. Im Kern ging es darum, dass verschiedene Prozesse wie z.B. das UI Driven Development erst durch eine passende Architektur ermöglicht wird. Sehr gut fand ich auch die Diskussion am Ende meines Vortrags. Das versprochene Whitepaper zu diesem Vortrag wird noch nachgereicht.
SharePoint veröffentlicht die Dokumentbibliotheken per WebDAV, d.h. man kann über \\<Servername>\sites\<ProjektName> beispielsweise auf die Dokumente eines TFS-Projektes zugreifen. Das funktioniert standardmäßig aber nicht von einem Windows 2003 Server aus. Hier muss der WebDAV Client zuerst aktiviert werden. Hierzu muss der Dienst "WebClient" gestartet werden. 
Ab dem 01.10.2008 werden Besitzer einer Visual Studio 2008 Team System Development Edition auch eine Visual Studio 2008 Team System Database Edition erhalten und umgekehrt. In Visual Studio 2010 werden diese beiden Produkte wohl zu einem verschmolzen. Weitere Informationen unter Visual Studio 2010 and .NET Framework 4.0 Overview im Kapitel "Better Together – Visual Studio Team System Development Edition and Database Edition"
Am 08.10.2008 haben wir Stefan Lieser zu Gast bei der .Net Developer-Group Ulm. Er wird in seinem Vortrag einige "Software Design Principles" vorstellen und erläutern wie diese helfen, Software wartbarer wird. Mitglieder und Gäste sind herzlich eingeladen. Weitere Infos unter http://www.dotnet-ulm.de/Treffen.aspx
Eine neue User-Group die sich speziell mit Team System beschäftigt wurde vor kurzem gegründet. Dabei handelt es sich um eine virtuelle usergroup, das heißt die Treffen finden in Second Life und über Office Live Meeting statt. Ich bin schon mal gespannt auf das nächste Treffen. Team System User Group - Virtual Edition
In inzwischen über 47 Videos werden in dieser Serie HowTos rund um das Thema Visual Studio Team System präsentiert. Kurz und verständlich bekommt man hier viele BestPractices und Tips. "How Do I?" Videos for Team System
Es ist wohl noch eine weile hin, bis wir Rosario wirklich nutzen dürfen. Brian Harry hat aber schon mal vorab veröffentlicht, welche Systemvoraussetzungen und Abhängigkeiten Rosario haben wird. So werden wohl unter anderem auch SQL 2005 und Office 2003 nicht mehr unterstützt. Dies gibt jetzt bereits die Möglichkeit, rechtzeitig zu planen und sich auf die Anforderungen ggf. entsprechend vorzubereiten. bharry's WebLog : Charting a course for TFS "Rosario"
Der Team Foundation Server bietet die flexible Möglichkeit ProcessTemplates individuell anzupassen. Diese ProcessTemplates enthalten die Definition der Workitemtypes (welche gibt es und welche Felder haben diese), die Workflows (was passiert wenn ich bei einem bestimmten Workitem eine bestimmte Aktion auslöse), und vieles mehr wie Standarddokumente etc. Dieses ProcessTemplate kann man nicht nur im Vorfeld definieren, sondern auch für laufende Projekte noch anpassen, was in der Praxis eine enorme Hilfe ist. Wie's genau geht beschreibt Christian Binder in einem zweiteiligen Blog-Beitrag. Teil 1 Teil 2
|
Copyright © 2010 Thomas. All rights reserved.
DasBlog 'Portal' theme by Johnny Hughes.
Pick a theme:
|
|