Open Source im professionellen Einsatz

Newsletter abonnieren
Seite durchsuchen

HEFTARCHIV | NEWS | E-BIBLIOTHEK | VIDEO | BLOGS | WHITEPAPER | EVENTS | ACADEMY | ABO | SHOP

user friendly

  Home  »  Heft & Abo  »  Heftarchiv  »  2005  »  04  »  Alles unter Kontrolle  

RSS-Feed der aktuellen News von Linux-Magazin Online Folgen Sie Linux-Magazin Online auf Twitter
Diesen Artikel druckenDiesen Artikel weiterempfehlen Diesen Artikel kommentieren Newsletter abonnieren
Share/Bookmark

Nachmachen hilft

Ein Test sollte möglichst wenig von anderen Bestandteilen des Systems abhängen, damit die Testsoftware eventuell auftretende Fehler auch an der richtigen Stelle meldet. In der Praxis bestehen aber in jedem System Abhängigkeiten, die das Testen schwieriger machen. Problematisch sind vor allem nicht immer verfügbare Ressourcen oder Funktionen, deren Aufruf unerwünschte Nebeneffekte hat. Je nach Art der Ressource muss der Programmierer hier andere Vorkehrungen zu treffen.

So genannte Mock-Objekte (Nachahmung) bieten die Möglichkeit, ein zu testendes Objekt von solchen Abhängigkeiten und Unwägbarkeiten zu isolieren, indem sie das Interface der benötigten Klasse nachahmen. Ein Mock ist also eine einfache Ersatzimplementation einer vom Produktionscode benötigten Klasse. Der Test parametrisiert ein Mock-Objekt mit den gewünschten Ein- und Ausgabewerten. Damit überprüft er, ob der getestete Code die richtigen Werte an das Objekt übergibt oder mit verschiedenen Rückgabewerten zurechtkommt. Mock-Objekte können auch ein praktischer Bestandteil des Test Driven Development sein, wenn man aus ihnen das Interface für den eigentlichen Produktionscode ableitet.

Selbstverständlich ist es keine Option, nur für den Test den Produktionscode zu verändern, damit statt des eigentlichen Objekts das Mock-Objekt aufgerufen wird. Schließlich sollen Unit-Tests automatisiert ablaufen. Um dieses Problem zu lösen, kann bereits im Produktionscode das entsprechende Objekt der Klasse als Parameter übergeben werden. Der Test übergibt stattdessen das Mock-Objekt an die Klasse. Dieser Ablauf erhöht aber möglicherweise die Komplexität des Code. Eine andere Lösung ist es, das Objekt nicht im Produktionscode zu initialisieren, sondern diesen Vorgang an eine eigene Methode zu delegieren. Die Testklasse wiederum überschreibt diese Methode, um das Mock-Objekt zurückzugeben. Ein Beispiel dazu findet sich inListing 3.

Es gibt mehrere Module, die die Erstellung von Mock-Objekten erleichtern. Flexmock[2] ist sehr einfach anzuwenden, bietet aber auch nur wenige Funktionen. Wer mehr Flexibilität benötigt, ist bei Test::Unit::Mock[3] gut aufgehoben. Beide sind als Rubygem[4] verfügbar. Die Installation gestaltet sich bei einem bereits vorhandenen Rubygems-Paket sehr einfach: »gem install flexmock« oder »gem install test-unit-mock«.

Listing 3:
»test_article.rb«

01 require 'test/unit'
02 require 'article'
03 require 'rubygems'
04 require_gem 'flexmock'
05 
06 class Article
07    attr_accessor :mock
08    def createConnection
09       return @mock
10    end
11 end
12 
13 class TestArticle < Test::Unit::TestCase
14    def setup
15       @article = Article.new
16       @year, @month = 2004,5
17       @url_base = 'http://www.linux-magazin.de' + 
18       '/Artikel/ausgabe/' + sprintf('%s/%02d', @year, @month)
19       @no_content = 'keine verwertbaren Daten'
20       @html = <<html
21       <UL><li>Aktuell: News aus der Linux-Welt
22       <li><A href="userspace/userspace.html">Userspace-Dateisysteme</A>
23       </UL><UL><LI></UL>
24 html
25    end
26 
27    def test_parse_articles_no_content
28       assert_nil(@article.parse_articles(@no_content))
29    end
30 
31    def test_parse_articles
32       result = @article.parse_articles(@html)
33       assert_instance_of(Array, result)
34       assert_equal(2, result.length, 'falsche Anzahl an Artikeln')
35    end
36 
37    def test_load_article_page
38       mock = FlexMock.new
39       mock.mock_handle(:get) { [nil, 'testhtml'] }
40       @article.mock = mock
41       html = @article.load_article_page(@year, @month)
42       assert_equal('testhtml', html)
43    end
44 
45    def test_load_article_page_network_error
46       mock = FlexMock.new
47       mock.mock_handle(:get) { raise SocketError, 'Netzwerkfehler' }
48       @article.mock = mock
49       assert_raise(SocketError) { @article.load_article_page(@year,@month) }
50    end
51 
52    def test_get_address
53       url = @article.send(:get_address, @year, @month, 'suffix')
54       assert_equal(@url_base + 'suffix', url)
55    end
56 
57    def test_read_articles
58       mock = FlexMock.new
59       mock.mock_handle(:get) { |param|
60          assert_equal(@url_base + '/index_html?print=y', param, 'Falsche URL')
61          [nil, @html]
62       }
63       @article.mock = mock
64       result = @article.read_articles(@year, @month)
65       assert_equal('Userspace-Dateisysteme',result[1][0])
66       assert_equal(@url_base + '/userspace/userspace.html',result[1][1])
67       assert_equal(2, result.length, 'falsche Anzahl an Artikeln')
68    end
69 
70    def test_read_articles_no_content
71       mock = FlexMock.new
72       mock.mock_handle(:get) { [nil, @no_content] }
73       @article.mock = mock
74       assert_nothing_raised { @article.read_articles(@year, @month) }
75       assert_instance_of(String, @article.read_articles(@year, @month))
76    end
77 
78    def test_read_articles_network_error
79       mock = FlexMock.new
80       mock.mock_handle(:get) { raise SocketError, 'simulierter Netzwerkfehler' }
81       @article.mock = mock
82       assert_nothing_raised { @article.read_articles(@year, @month) }
83       assert_instance_of(String, @article.read_articles(@year, @month))
84    end
85 end

Internetzugriff testen

Ein Beispiel: Die Website des Linux-Magazins bietet die Inhaltsverzeichnisse aller Ausgaben seit 1994. Die Klasse »Article« (Listing 2) liest zu einer bestimmten Ausgabe die Titel der Artikel und - falls vorhanden - die URL des Artikelinhalts aus. Der Zugriff auf eine Quelle im Internet ist aber fehleranfällig und vergleichsweise langsam. Ein Mock-Objekt macht das Testbeispiel unabhängig von externen Ressourcen.

In der gekürzt abgebildeten Klasse »Article« in Listing 2 übernimmt die Methode »read_articles« Jahr und Monat des gewünschten Hefts und gibt eine Liste mit den Titeln und URLs der Artikel zurück. Der komplette Programmcode ist auf dem Server des Linux-Magazins verfügbar[6]. Die Testklasse in Listing 3 testet auf einige der wichtigsten Fehlerquellen wie fehlende Netzwerkverbindung oder nicht interpretierbare Rückgabewerte.

Diesen Artikel druckenDiesen Artikel weiterempfehlen Diesen Artikel kommentieren Newsletter abonnieren
Share/Bookmark
Ähnliche Artikel
Babylon zu fünft Populäre Programmiersprachen treten gegeneinander an
Geistertanz Die Skriptsprache Boo
Babylon zu fünft Populäre Programmiersprachen treten gegeneinander an
PC statt Bunsenbrenner Chemoinformatik mit dem Chemical Development Kit
Code-Vehikel Alternativen zu den populären Programmiersprachen
Alternativ-Baukästen GUI-Programmierung mit Fltk, Wx-Widgets und EFL
Whitepaper
Open Source Datenintegration in der Praxis: Fallstudien und Anwendungsbeispiele (Folge 2)

Der zweite Teil des Open Source Datenintegration in der Praxis: Fallstudien und Anwendungsbeispiele White Papers beleuchtet anhand weiterer ausgewählter Case Studies die Implementierung von Open Source Datenintegration in der Praxis und benennt die daraus resultierenden Vorteile.

Download PDF (Registrierung erforderlich)
Usage Landscape Enterprise Open Source Data Integration

Die Nachfrage nach Datenintegrationslösungen für Unternehmen ist zunehmend gestiegen und vor allem das Interesse an Open Source Technologien wird immer größer. Doch wie und von wem werden Open Source Datenintegrationslösungen genutzt und welches Nutzungsverhalten lässt sich daraus ableiten? Das vorliegende White Paper präsentiert die Erfahrungswerte von über 1000 Open Source Nutzern und liefert fundierte Antworten auf diese Fragen.

Download PDF (Registrierung erforderlich)
Kommentare (0)