Jun 122010
 

Jeder Entwickler kennt sicherlich das Problem, dass seine eigenen Tests häufig nicht aussagekräftig genug sind.
Der 100% identische Programmcode kompiliert bei Entwickler A, nicht aber bei Entwickler B („wirklich 100% gleich?“ „Ja, klar.“ „Auch Komponente X“ „Sicher“ „Und du hast die selbe Version von Lib Y?“ „Uhoh…“).
Noch schlimmer: Bei beiden kompiliert der Code, aber das Laufzeitverhalten unterscheidet sich. Klar das hieraus Probleme resultieren, z.B. wird es zur Glückssache,  gezielt Fehler zu reproduzieren, um sie zu debuggen.
Solche Phänomene treten besonders häufig auf bei Software-Projekten  mit  diesem „Gütesiegel“:

Tritt das aber zu oft auf, hört es irgendwann auf lustig zu sein und man sucht Wege, diese Effekte zu vermeiden. Ein hervorragender Weg, dieses  Ziel zu erreichen, führt in Richtung dieses Prädikats:

Was dahinter steckt, erfährt man besser gleich von Quelle (aufs Logo klicken), ist jedenfalls eine längere Geschichte mit Happy End für jeden, der dabei mitmachen will.

Denn ein Prinzip, das ein ‚Clean Code Developer‘ befolgen sollte, ist Continuous Integration. Das klingt erschreckend nach Buzz-Word, ist aber tatsächlich sehr schön präzisierbar: Ich bringe es mal folgendermaßen auf den Punkt:

Wer Continuous Integration betreibt, hat ein Testsystem, auf dem jede Code-Änderung eine Reihe von festgelegten Tests unter immer gleichen Bedingungen durchläuft.

Das soll keine Neudefinition sein und ist vielleicht zu einfach gesagt oder unvollständig, aber dafür ist es einfach zu verstehen. Denn dieser Artikel soll unter Anderem die Angst davor nehmen, es einfach zu tun.
Deshalb schockiere ich auch nicht mit der geballten Ladung eines Lehrbuch-CI-Systems, sondern skizziere eine auch für kleine Teams praxistaugliche, einfache Variante von CI.

Folgende (gratis verfügbaren) Komponenten setze ich auch beruflich sehr erfolgreich zusammen ein:

  • JetBrains TeamCity: CI-Server, gibt’s als kostenlose Version (kein Trial, die Limitierungen sind sehr moderat)
  • NAnt (.NET-Portierung der Ant-Build-Skripts)
  • Subversion (Concurrent Versioning System (CVS))

An dieser Stelle ist es wohl angebracht, zu erwähnen, dass ich CI für .NET-Projekte (C#, WPF) einsetze. Das beeinflusst sicherlich die Wahl der Tools, Maven z.B. ist für Java quasi gesetzt, für mich kaum relevant.

Mit dieser Kombination kann man schon so einiges erreichen., und ich verrate auch, wie:

Setup des CI-Systems:

Schritt 1) Alles ins CVS

Gibt es noch Entwickler oder gar Teams, die ohne CVS arbeiten? Falls ja, sollten sie es schleunigst ändern. Meine Empfehlung für Tools lautet: VisualSVN Server (kostenlos und einfach zu installieren und konfigurieren), TortoiseSVN Client auf jedem Entwicklingsrechner, VisualSVN (kostenpflichtig) oder AnkhSVN (aktuelle Version um Längen besser als frühere) als VisualStudio-PlugIn. Wichtig ist dabei, dass wirklich ALLES im SVN ist, jede Konfigurationsdatei, Skripts, die vom Build-Prozess oder für’s Deployment durchlaufen werden, Projekt- und Solution-Files…
Außerdem ist es sinnvoll, ein Projekt auch im SVN zusammenzuhalten statt aus vielen Quellen zusammenzupuzzlen – SVN bietet hierfür auch die Möglichkeit, mit sog. ‚Externals‘ verteilte Quellen zu verlinken und so wieder zusammenzuführen.

Dies ist übrigens ein eigenes Prinzip für jeden Clean Code Developer, daher streife ich es hier nur. Es wird für die nächsten Schritt dringend benötigt. Der CI-Server wird in der Regel so konfiguriert, dass er für jedes Projekt auf einen Zweig des SVN „lauscht“. Er schneidet also mit, wenn jemand dort eine Änderung eincheckt und startet daraufhin den nächsten CI-Build.

Schritt 2) Build-Skript vorbereiten

Die einfachste Variante, um CI an den Start zu bringen, ist es wohl, TeamCity einfach ein .sln-File zu nennen, das er kompilieren soll. Hier hat  man es dann aber schwerer, wenn man später noch weitere „Build-Targets“ hinzufügen will, z.B. UnitTests starten oder ein Setup erstellen.
Für mich hat sich NAnt als sehr geeignet erwiesen, auch wenn es gegen Rake & Co. etwas altmodisch wirkt. Effizient ist es immer noch, und da es schon so lange lebt, gibt es auch reichlich Community Input dazu im Netz.

Die Erklärung eines NAnt-Skripts spare ich mir an dieser Stelle, ich skizziere nur kurz, was sich bewährt hat beim Weg ins CI:

  1. NAnt-Skript auf Level der Solution anlegen, zum Start ein Beispiel aus dem Netz fischen.
  2. NAnt-Skript solange „tunen“, bis es auf dem lokalen Entwicklerrechner funktioniert.
  3. Alle Pfade im Skript müssen relativ sein und „nur nach unten“ zeigen, also tiefer ins SVN-Repository. Logisch, nur so sind alle verwendeten Anteile auch für den CI-Server verfügbar.
  4. Build-Skript natürlich auch einchecken.

Schritt 3) TeamCity Konfigurieren und Feinschliff

TeamCity ist erstaunlich intuitiv bedienbar, zumindest für die meisten Entwickler.Der schwierigste Teil ist wohl das Vorbereiten des Servers: Er muss für .NET-Projekte natürlich bevorzugt auf Windows basieren, also IIS als WebServer verwenden. Außerdem müssen die notwendigen SDKs (statt VisualStudio) installiert sein, die zum Build benötigt werden. Die Installation selbst ist dann fast selbsterklärend bzw. der Hersteller erklärt sie gut genug.

Dann das erste Projekt erstellen: richtigen SVN-Zweig konfigurieren, Build-Methode wählen und schon geht’s los. Hierbei stellt sich dann heraus, ob das Build-Skript auch wirklich keine speziellen Voraussetzungen an den CI-Rechner stellt ;O)
Am besten startet man das Build-Skript manuell direkt auf dem Server (ohne TeamCity), bis es läuft. Das beschleunigt das Testen etwas.

Hat man das erledigt, sieht man schon, dass der Build nach jedem SVN-Commit losläuft und rot oder grün meldet. Aber es fehlt noch etwas: das sog. „Artefakt“. Jeder Build sollte irgendetwas erzeugen, dass als Endergebnis gewollt ist, etwas bauen eben. Entweder ist das das kompilierte Programm in Form einer exe oder eine Installationsdatei, oder noch etwas anderes. Was auch immer, es muss vom Build-Skript erzeugt werden und dann als Artefakt konfiguriert werden (einfach relativen Pfad von Build-Skript eintragen), dann kann es jeder User (auch die Nicht-Entwickler) vom CI-Server herunterladen und einfach starten. So ist ein BugFix ruckzuck an die QS zum Test übermittelt, und im CI-Server steht sogar die Versionshistorie, wo z.B. der Jira-Bug-Tracker referenziert wird.

Schritt 4 (optional): FREUEN!

So macht das Entwickeln gleich viel mehr Spaß, man verbringt deutlich mehr Zeit mit der Wertschöpfung und weniger mit nervigen Ärgereien über mysteriöse Systemdivergenzen. Die Freude steigt, wenn man sich weitere Features anschaut, die der CI-Server bietet:

  • Benachrichtigung bei fehlgeschlagenem Build/Test via E-Mail, Jabber, Tray-Tool, …
  • Markierung von Builds mit Tags (z.B. als Stable, unstable, tested, released…)
  • Historie von Build-Zeiten, Test-Counts, …
  • Anzeige von SVN-Diffs und -Historie über die Webseite (kein Client nötig für nicht-Entwickler)
  • SVN-Commit ablehnen, falls er nicht zu einem erfolgreichen Build führt

Nächste Schritte:

Eine der gr0ßen Stärken von TeamCity ist die hervorragende Integration von NUnit (oder anderer UnitTests) und NCover. Jeder CI-Build sollte nach Möglichkeit alle Unit-Tests des kompilierten Codes ausführen, TeamCity zeigt dann automatisch an, wie viele Tests erfolgreich waren, führt Statistiken (auch über Anzahl und Laufzeit der Tests), und meldet vor allem zurück, wenn Unit-Tests fehlgeschlagen sind. Weiterer Vorteil: die UnitTests laufen auf einem objektiven System, wenn bei Entwicker A der Test B läuft, bei Entwickler B nicht, entscheidet künftig der CI-Server, welches System „Recht hat“.

NCover empfiehlt sich eher für Nightly-Builds und manuell getriggerte Builds, da es etwas mehr Zeit braucht um die Reports zu generieren. CI-Einbindung kann helfen, die TestCoverage längerfristig zu beobachten, jeder einzelne Report ist natürlich unheimlich wertvoll, um besonders testwürdige Stellen zu identifizieren, aber das hat eigentlich nur mit NCover zu tun, weniger mit CI. Der CI-Server kann hier auch Geld sparen, denn NCover kostet ja Geld pro Lizenz – ein Server kann für n Entwickler die notwendigen Reports generieren.

 Posted by at 21:21

  One Response to “Continuous Integration (CI) mit TeamCity, NAnt und SVN”

  1. […] PowerCommands und Pro Power Tools für VisualStudio 2008 + 2010    Continuous Integration (CI) mit TeamCity, NAnt und SVN […]

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)

n/a