Archiv

Archive for Dezember 2011

Leichter testen mit Moq

30. Dezember 2011 1 Kommentar

Moq ist ein kleines und sehr einfaches Mock-Framework für .Net / C#. Obwohl es solche Frameworks wie Sand am Meer gibt, so sticht Moq doch heraus. Allzu oft ist das Aufsetzen eines Mocks sehr umständlich und der Test Code wird unnötig kompliziert. Moq dagegen nutzt eine sehr klare Syntax und verfügt über ein praxisorientiertes Standardverhalten.

 

Wozu Mocks?

Bei Unit-Tests möchte man möglichst nur eine kleine Einheit testen. Meistens aber gibt es Abhängigkeiten zu anderen Einheiten die man für diesen Test ignorieren möchte. Ist man am Erstellen eines Rabattsystems für einen Warenkorb möchte man nicht jedes Mal überprüfen ob der Warenkorb korrekt aus der Datenbank geladen werden kann.

Es kann auch sein das die Abhängigkeiten für die zu testende Einheit noch gar nicht existieren. Soll ein Client und ein Service parallel entwickelt werden einigt man sich zuerst auf eine Schnittstelle. Bis der Service läuft muss man mit dem Client gegen etwas testen können. Mocks können dieses „etwas“ sein und den Service simulieren.

Was zwischen 2 Systemen geht funktioniert genauso auch mit gewöhnlichen Klassen. Hier kann man ein Interface definieren und erzeugt daraus einen Mock bis man eine richtige Implementierung hat.

 

Moq verwenden

Moq installiert man am besten über NuGet. Man bekommt so die aktuelle Version und kann später sehr einfach das installierte Paket aktualisieren. Wer dies nicht will findet den Code auf der Projektseite. Die Referenz auf Moq braucht es nur im Testprojekt, das Projekt mit dem produktiven Code muss von Moq nichts wissen.

Bevor man mit Moq loslegt sollte man einen Blick auf den QuickStart Artikel im Wiki werfen. Dort werden die häufigsten Anwendungsfälle mit Codebeispielen gezeigt.

Für mein Beispiel nutze ich das Interface IPersonService und die Klasse Person:

public interface IPersonService
{
    Person GetPersonById(int id);
}

public class Person
{
    public string LastName { get; set; }
    public string FirstName { get; set; }
}

Ich möchte erreichen dass immer wenn ich die Methode GetPersonById(1) aufrufe eine bestimmte Instanz von Person zurückgegeben wird. Dazu genügt es die Person zu instantzieren und 2 Zeilen Code um Moq aufzusetzen:

[TestMethod]
public void ShowHowToMockAnInterface()
{
    Person person = new Person(){LastName = "Graber", FirstName = "Johnny"};
            
    var mock = new Mock<IPersonService>();
    mock.Setup(service => service.GetPersonById(1)).Returns(person);

    Assert.AreEqual(person, mock.Object.GetPersonById(1));
}

Wer sich bisher nicht mit Lambda-Ausdrücken beschäftigt hat wird vielleicht ein wenig verwirrt sein. Ich finde den Code so aber sehr leserlich und verständlich. Will man später seine Methode umbenennen wird mit den Tools von Visual Studio dieser Aufruf gefunden. Würde man statt dem Lambda einen String benutzen ist dies nicht immer der Fall.

Um eine realistischere Verwendung von Moq zu zeigen soll nun die Klasse Worker die Person holen. Diese kennt nur das Interface und weiss nichts von Moq:

public class Worker
{
    private readonly IPersonService _personService;

    public Worker(IPersonService personService)
    {
        _personService = personService;
    }

    public Person GetPerson()
    {
        return _personService.GetPersonById(1);
    }
}

Der dazugehörige Test sieht fast gleich aus:

[TestMethod]
public void ShowUsageOfMock()
{
    Person person = new Person() { LastName = "Graber", FirstName = "Johnny" };

    var mock = new Mock<IPersonService>();
    mock.Setup(service => service.GetPersonById(1)).Returns(person);   

    Worker worker = new Worker(mock.Object);

    Assert.AreEqual(person, worker.GetPerson());
}

 

Stabile Tests

Was mir an Moq besonders gefällt ist das Standardverhalten. Wird eine Methode des Interfaces aufgerufen die man nicht gemockt hat liefert Moq den Standardwert zurück. Wenn ich eine neue Methode im Interface hinzufüge und diese im Worker aufrufe funktionieren meine bisherigen Tests auch weiterhin.


public interface IPersonService
{
    Person GetPersonById(int id);

    bool IsActive(Person person); // Neue Methode
}

public class Worker
{
    ...
    public Person GetPerson()
    {
        Person p = _personService.GetPersonById(1);
        _personService.IsActive(p); // neuer Aufruf
        return p;
    }
}

Durch dieses Verhalten sind die Tests weniger Fehleranfällig. Wenn ich aber einen Fehler will sobald andere Methoden von meinem Mock aufgerufen werden kann ich dies im Konstruktor aktivieren:

var mock = new Mock<IPersonService>(MockBehavior.Strict);

 

Wo Moq an seine Grenzen stösst

Wie viele Mock-Frameworks kann auch Moq keine statischen Klassen und Methoden mocken. Arbeitet man an einem neuen Projekt kann man diese Einschränkung umgehen in dem man möglichst auf statischen Methoden verzichtet und wo nicht anders möglich diese in einen Wrapper packt.

Will man aber in einem grossen bestehenden Projekt mit vielen statischen Methoden mit Unit Tests beginnen ist die Einschränkung von Moq ein Problem. In dem Fall sollte man sich TypeMock und JustMock anschauen. Diese Frameworks umgehen die Einschränkungen mit statischen Klassen und Methoden indem sie sich sehr tief im .Net Framework einklinken und Methodenaufrufe umleiten.

 

Fazit

Moq ist ein sehr hilfreiches Werkzeug für Unit Tests. Es macht genau was man von ihm erwartet und braucht dazu nur eine minimale Konfiguration. Dadurch kann man sich auf das konzentrieren was man wirklich machen will: Mit Unit-Tests neue Funktionalität einbauen.

 

Schlagworte: , ,

Buch-Rezension zu “Rails 3 in Action”

25. Dezember 2011 Kommentare aus

Rails 3 in Action” von Ryan Bigg und Yehuda Katz erschien im September 2011 bei Manning. Ein Buch für Einsteiger in Rails kam mir gerade sehr gelegen, da ich nach einigem Experimentieren mit Ruby nun gerne eine Webanwendung mit Rails entwickeln wollte.

Dieses Buch liest sich sehr flüssig und man bemerkt schnell dass die Autoren wissen wovon sie schreiben. Will man das gelesene aber selber umsetzen bemerkt man leider ebenfalls sehr bald die ersten Probleme. Wichtige Punkte und Details werden erwähnt, aber nicht wirklich gut hervorgehoben. Oft bemerkt man die entscheidenden Stellen so erst nach längerer Fehlersuche im selber geschriebenen Code.

 

Von rails new bis zum deployment

Durch das ganze Buch hindurch wird ein Issue-Tracking-System Schritt für Schritt aufgebaut. Man beginnt mit rails new und bekommt im weiteren Verlauf gezeigt wie man mit dem MVC-Pattern eine Webanwendung entwickelt.

Neben einfachen CRUD-Oberflächen (zum Erstellen, Anzeigen, Editieren und Löschen von Objekten) wird auch auf verschachtelte Ressourcen eingegangen. Wie man Benutzer Authentifiziert und Autorisiert fehlt ebenso wenig wie das Versenden von E-Mails.

Hat man seine Anwendung zusammen muss diese auch deployt werden. Neben einer Anleitung zum Konfigurieren von Capistrano wird auch erklärt wie man Apache oder Nginx konfigurieren muss, damit die Anfragen an die Rails-Anwendung auch beantwortet werden.

Die Autoren zeigen sehr schön welche Schritte nötig sind um von einer Idee zu einer installierten Anwendung zu kommen. Die einzelnen Schritte sind dabei sehr gut durchdacht und man sieht wie alles zusammen passt. Das Konzept dieses Buches ist top, leider wird durch etliche kleine Fehler der Praxisnutzen bald einmal reduziert.

 

Erst ein Test, dann die Funktionalität

Mit Ausnahme der grundlegenden Erklärung im ersten Kapitel wird über das ganze Buch hinweg immer erst ein Test geschrieben bevor die Funktionalität implementiert wird. Als Werkzeug fürs Behavior-Driven Development (BDD) dienen Cucumber und RSpec.

Mir hat dieser Ansatz sehr gut gefallen. Da es bei Ruby keinen Compiler gibt der einem auf Fehler in der Syntax hinweist sind Tests unabdingbar – ausser man will wirklich bei jeder kleinen Änderung alles manuell durchtesten…

Neben Tests der Weboberfläche wurde auch gezeigt wie man den Versand von E-Mails oder Funktionsaufrufe in JavaScript kontrollieren kann. Diese komplexeren Tätigkeiten werden sonst meist ausgelassen. Hier hat man für einmal alles schön beisammen und auch verständlich erklärt.

Sehr gut fand ich auch dass nach jedem Teilschritt immer gleich ein commit ins Git-Repository gemacht wurde. So gewöhnt man sich schnell an dieses Versionierungssystem und bekommt ein Gefühl dafür wie oft man committen sollte.

 

Lange Entstehungsgeschichte

Das Buch wurde 2008 gestartet und hatte ursprünglich Merb als Thema. Als Merb Ende 2008 in Rails aufging wechselte auch der Fokus des Buches. Die lange und wechselhafte Geschichte bemerkt man als Leser stellenweise auch im fertigen Buch.

Als Beispiel: Die Funktion f.error_messages wird zum Anzeigen der Fehler in Formularen verwendet. Mit Rails 3 wurde diese Methode entfernt und ist nun nur noch über ein zusätzliches Plug-in nutzbar. Ich hätte es begrüsst wenn man statt dem Plug-in gleich die aktuelle Variante von Rails verwendet hätte.
Gleiches gilt für die Syntax der Migration-Dateien. Was im Buch steht hat nicht viel mit dem Gemeinsam was einem Rails 3.1 generiert. Dies verwirrt den Leser nur unnötig.

 

Cucumber entfernt die Stützräder

Anfangs Oktober 2011 entschied man sich bei Cucumber-Rails die Hilfsfunktionen in web_stebs.rb zu entfernen. Die darin enthaltenden Schrittdefinitionen ermöglichen einem einen schnellen Einstieg in Cucumber, entsprechen aber nicht ganz dem Sinn von BDD. Da viele Tests aus diesem Buch darauf aufbauen hat man nun ein Problem wenn man versucht die Beispiele umzusetzen.

Im Forum zum Buch gibt es bereits einige Links zu Beispielen die die nötigen Änderungen aufzeigen. Ich finde diese Tests lesbarer als was im Buch steht – von dem her kann ich die Begründung für die Änderung in Cucumber nachvollziehen. Wem ein Umbau zu viel Aufwand ist kann in seinem Gemfile die letzte Version von Cucumber-Rails mit web_stebs explizit angeben:

gem 'cucumber-rails', '1.0.6'

 

Was mir fehlt

Entwickelt man eine ganze Anwendung streng nach Test-First hat man am Ende genau den Code geschrieben der gemäss den Anforderungen nötig ist. Gibt es keine Anforderungen an die Oberfläche sieht diese am Ende sehr trist aus. Auch wenn das Thema Rails und nicht CSS ist, ich hätte es sehr begrüsst wenn man in einem Kapitel auf die Gestaltung der Oberfläche eingegangen wäre. Nur ein Link auf eine CSS-Datei ohne grosse Erklärung finde ich ein wenig mager.

Die letzten beiden Kapitel zu Engines und Rack-basierten Applikationen passten für mich nicht wirklich ins Buch. Statt diesen Spezialthemen wäre mir ein Kapitel über das Debuggen einer Rails-Anwendung oder eine Hilfestellung für die häufigsten Probleme lieber gewesen.

In die Probleme rennt man spätestens wenn man die Anwendung in der Produktionsumgebung startet. In Rails 3.1 wurde die Asset Pipeline eingeführt. Da diese nur in der Produktion aktiv ist bemerkt man beim Programmieren und testen nichts. Die Probleme treten erst auf wenn man auch gleich noch mit der Konfiguration des Webservers am kämpfen ist…

Ohne zusätzliche Unterlagen bleibt man so auf der Zielgerade liegen. Dies finde ich für ein Buch das von „Leadern“ der Rails-Community für Anfänger geschrieben wurde sehr schlecht. Ich verstehe das sich Rails sehr schnell entwickelt und man nicht alles zum vornherein beachten kann. Aber mindestens in die Errata müssten solche Sachen zügig aufgenommen werden, nicht erst nach einigen Wochen oder Monaten. Macht man auch dies nicht darf einem eine schlechte Bewertung bei Amazon nicht erstaunen.

 

Fazit

Rails 3 in Action liest sich flüssig und setzt kein grosses Vorwissen voraus. Der Ansatz alles mit Test-First zu machen finde ich gut, durch die Änderungen an Cucumber sollte man das Buch aber sehr bald überarbeiten.

Ich konnte mein Ziel erreichen und meine eigene Rails-Applikation mit dem hier gelernten umsetzten. Bis diese aber in einer Produktionsumgebung lief hatte ich viele Probleme zu lösen für die mir dieses Buch keine Antwort liefern konnte.

Viele kleine Fehler (und einige grosse Lücken) machen ein sehr gutes Buchkonzept schnell zunichte. Mir bleibt die Hoffnung auf eine Version 2 die diese Probleme behebt. Bis dahin kann ich dieses Buch Anfängern leider nicht weiterempfehlen.

 

Zum Buch

Rails 3 in Action” von Ryan Bigg und Yehuda Katz, 2011 Manning, ISBN: 978-1-93518-227-6, 592 Seiten, Englisch

Schlagworte: ,
Folgen

Erhalte jeden neuen Beitrag in deinen Posteingang.

Schließe dich 295 Followern an