Analyzing the JRuby test suite
One of the biggest Ruby unit test suites in existance is
JRuby’s, which weights (all external
suites included) a whopping 39kLOC. It is split into some big
subprojects:
- The JRuby test suite (10kLOC)
- The Rubinius test suite (8.4kLOC)
- The Rubicon test suite (5.8kLOC)
- The BFTS (4.3kLOC)
- The Matz Ruby Interpreter test suite (4kLOC)
(The other ~6kLoc are benchmarks and Java unit tests, which are not
relevant here.)
I have analyzed each of them according to these factors:
- Number of test cases (contexts)
- Number of tests (specifcations)
- Number of assertions (shoulds)
- how many are negated
- what do they test
I’ll go through each test suite and present the numbers. Please note
that they were made with some hacked-together scripts and may not be
totally accurate, but they should show the big picture. All numbers are
based on checkout r3767, last changed 2007-05-30 07:52:31 +0200.
The JRuby test suite
The JRuby test suite uses minirunit and Test::Unit for its tests.
The minirunit part has 2747 assertions, but no specially marked test
cases. The most used assertions were:
- test_equal (1695)
- test_ok (400)
- test_exception (277)
- test_tree (118)
- test_no_exception (73)
- test_check (69)
There are a lot non-xUnit assertions defined, which only make up a
small part of the suite: the often used ones are test_tree (assertions
about the parse tree) and test_marshal.
Negated assertions occur as test_no_exception
and test_fail, and make
up about 5.6%. (Including 71 cases of test_ok with a negated expression.)
The small mri test suite (minirunit too) has 260 assertions, of which
226 are test_ok,
19 test_equal and
15 test_check.
The Test::Unit part of the suite has 40 test cases with 244 tests.
There are 568 assertions, of which 33 (5.8%) are negated. Most used are:
- assert_equal (331)
- assert_raises (38)
- assert_parse_only (38)
- assert_inspect_evaled (28)
- assert_argerr (20)
- assert_cycle (18)
Other non-xUnit assertions are: test_to_yaml,
test_eval_inspected,
test_path_segments.
The Rubinius test suite
The Rubinius test suite uses a small clone of
RSpec called mini_rspec. It contains
117 contexts with 1046 specifications. There are 2513 shoulds, of
which 15 are negated (0.6%).
The most used shoulds were:
- should == (1765)
- should == true (304)
- should == false (106)
- should_raise (141)
- should == nil (87)
- should_include (35)
should_receive (12) was the only custom should found.
The Rubicon test suite
The Rubicon test suite uses Test::Unit and has 42 test cases with 480
tests. Of 2316 assertions, 18 are negated (0.8%).
Most used assertions were:
- assert_equal (1941)
- assert_flequal (107)
- assert_nil (102)
- assert_raise (79)
- assert_same (30)
Non-xUnit assertions are assert_bag_equal.
The BFTS
The Big Fucking Test Suite consists of 13 Test::Unit test cases with
359 tests. There are 1914 assertions, 34 are negated (1.8%).
Most used where:
- assert_equal (1706)
- assert_nil (85)
- assert_raises (76)
- assert_same (23)
There are no non-xUnit assertions in the BFTS.
The MRI test suite
The MRI test suite consists of 46 Test::Unit test cases with 166
tests. There are 1178 assertions, of which 28 are negated (2.3%).
Most used were:
- assert_equal (982)
- assert_raises (69)
- assert_nil (43)
- assert_instance_of (17)
Non-xUnit assertions are: assert_arity,
assert_eval_inspected,
assert_inspect_evaled.
Conclusion
N.B.: These unit test suites test language implementations and not
highlevel libraries or applications, therefore these results are not
directly applicable for general testing frameworks. It would be
great if someone could do tests like these for big libraries (Rails)
or big applications.
The main assertions used are tests for equality (and especially true,
false and nil) and tests for exceptions. Only a small part of
assertions are negated, and these mostly check that nothing is raised.
xUnit assertions cover over 90% of all assertions, but custom and
user-defined assertions simplify testing by abstracting common code
and making test cleaner and clearer.
Future testing frameworks (especially for language test suites) should
optimize for these features.
NP: Bob Dylan—Forever Young
Verweigerung
Endlich (nach über zwei Monaten) ist mein
Kriegsdienstverweigerungsantrag durch, und ich darf somit den Dienst an der
Waffe verweigern.
Da meine Verweigerung anders als die vielen anderen, die man so im
Netz findet, nicht mit religiösen Gründen oder der Erziehung wegen
argumentiert, könnte sie auch anderen Verweigerern nützlich sein.
Hier daher der Volltext.
Beweggründe für meine Kriegsdienstverweigerung
Ein Krieg ist ein Waffenkonflikt, der unter Einsatz erheblicher Mittel
ausgeführt wird.
Unter Ausübung von Gewalt wird also versucht, einen Konflikt zu
bewältigen, oder eigentlich, wie Clausewitz schreibt: “den Gegner zur
Erfüllung unseres Willens zu zwingen”.
Aus eigener Erfahrung weiß ich aber, dass Gewalt aber nie eine Lösung
ist, sondern stets Gegengewalt erzeugt: an Konfliktbekämpfung ist
daher nicht zu denken. Es ist jedoch meine feste Überzeugung, dass es
für jeden Konflikt eine friedliche und dauerhafte Lösung gibt.
Die Anwendung von Gewalt als versuchtes Mittel zur Konfliktbewältigung
ist jedoch gegen die Natur des Menschen, oder genauer: gegen die
menschliche Natur. Unsere Menschlichkeit erlaubt es uns, Konflikte
auf friedlichem Wege zu lösen, ohne zu töten und zu zerstören.
In der Geschichte gibt es genug Beispiele dafür, dass eine friedliche
Lösung von Konflikten möglich ist, als Beispiel seien hier Mahatma
Ghandi und Martin Luther King genannt.
Ein weit größeres Problem als die Sinnlosigkeit eines Krieges ist
jedoch das Leid und die Grausamkeit für die betroffenen Menschen:
Sowohl die Zivilbevölkerung als auch die Soldaten, die ja trotzdem
Menschen sind, werden oft schwer verwundet und tragen physische und
auch große psychische Schäden davon.
Nicht nur durch meine Erziehung, sondern auch durch die reine
Vernunft ist es mir daher unmöglich Kriegsdienst zu leisten. Dieser
schließt nämlich nicht nur den Dienst an der Waffe ein, deren Zweck es
ja ist, den Gegner durch letale Gewalt zu kontrollieren, sondern
beinhaltet sämtliche andere Tätigkeiten, deren Sinn in der Planung,
Vorbereitung und Durchführung von Waffengewalt endet.
Selbstverständlich bin ich nicht der erste, der zu diesem Schluss
kommt. So fordert Kant, der wohl wichtigste deutsche Philosoph, in
seiner Schrift “Zum ewigen Frieden” von 1795: “Stehende
Heere (miles pepetuus) sollen mit der Zeit ganz aufhören, “[d]enn
sie bedrohen andere Staaten unaufhörlich mit Krieg, durch die
Bereitschaft, immer dazu gerüstet zu erscheinen”. Auch wenn die
Bundeswehr nur als Verteidigungsarmee gedacht ist, so hat sie doch ein
stehendes Heer, und kann daher stets Krieg führen. Wieviel Leid wäre
der deutschen und der Weltgeschichte erspart worden, hätte man auf Kant gehört.
Kant erkennt weiterhin, dass Frieden kein Naturzustand ist, sondern
gestiftet werden muss, und dabei stimme ich gänzlich zu. Die Kraft
und Vernunft der Menschen sollte daher dazu verwendet werden, Frieden
zu stiften, und nicht etwa Kriege zu führen. So will auch ich meine
Kraft zum Wohl der Bevölkerung und nicht des Krieges verwenden und
Zivildienst leisten.
Kein Mensch will sich erschießen lassen, will gefoltert werden oder
für einen nichtigen Zweck wie Landesgrenzen sterben. Selbst wenn mein
eigenes Leben auf dem Spiel stünde, würde ich aber auch nicht
schießen, foltern oder töten können; nicht aus eigener Überzeugung,
und schon gar nicht auf Befehl.
Befehl und Gehorsam, wie sie im Kriegsdienst an der Ordnung sind,
stehen dort über der Vernunft: Der Soldat hat zu befolgen, was ihm
befohlen wurde. Diese Aufgabe der Vernunft, und der damit
einhergehende Verlust der Selbstkontrolle, kann grausamste Folgen
annehmen, die angesichts der deutschen Geschichte keiner weiteren
Erläuterung bedürfen. Als aufgeklärter Mensch ist es für mich
unvorstellbar, durch Zwang zum Gehorsam zu einem gedankenlosen
Ausführungsorgan reduziert zu werden.
Ich habe mich ernsthaft mit der Vorstellung, auf Befehl Menschen töten
zu müssen, auseinandergesetzt und stellte fest, dass allein schon die
Vorstellung davon weder mit meinem Gewissen noch mit meinem Weltbild
vereinbar ist.
Ich bin daher felsenfest überzeugt, auf keinen Fall zum Teil dieser
Kriegsmaschinerie werden zu wollen, und anderen Menschen, seien es
sogenannte “feindliche” Soldaten oder auch der Zivilbevölkerung,
Leid jeglicher Art anzutun, auf sie zu schießen, sie zu verletzen oder
gar zu töten.
Der Bundeswehr oder irgendeiner anderen Streitkraft zu dienen würde meine
Wertvorstellungen massiv untergraben.
Um meiner Überzeugung zu folgen und mich aktiv dafür einzusetzen, sehe
ich den Zivildienst als eine gute Möglichkeit an, meine Pflicht als
deutscher Bürger gegenüber Staat und Gesellschaft zu erfüllen. Ich
habe mich bereits nach Zivildienststellen erkundigt und mich schon bei
mehreren beworben. Ich will die mir vom Staat gegebene Chance nutzen,
um Erfahrungen zu sammeln, die mir auf meinem weiteren Lebensweg
bestimmt nützlich sein werden.
Daher bitte Sie hiermit darum, meine Kriegsdienstverweigerung nach
Artikel 4, Absatz 3, Satz 1 des Grundgesetzes anzuerkennen.
Für mich hat’s geklappt, aber alles natürlich ohne Gewähr.
Viel Erfolg.
NP: Bob Dylan—Masters Of War
Rack 0.2, a modular Ruby webserver interface
Today I’m proud to release Rack 0.2.
Rack provides a minimal, modular and adaptable interface for developing
web applications in Ruby. By wrapping HTTP requests and responses in
the simplest way possible, it unifies and distills the API for web
servers, web frameworks, and software in between (the so-called
middleware) into a single method call.
The exact details of this are described in the Rack specification,
which all Rack applications should conform to.
Supported web servers
The included handlers connect all kinds of web servers to Rack:
- Mongrel
- Mongrel/Swiftcore (require it before Rack.)
- WEBrick
- FCGI
- CGI
Any valid Rack app will run the same on all these handlers, without
changing anything.
Supported web frameworks
The included adapters connect Rack with existing Ruby web frameworks:
These frameworks include Rack adapters in their distributions:
- Ramaze
- Maveric
- Racktools::SimpleApplication
Available middleware
Between the server and the framework, Rack can be customized to your
applications needs using middleware, for example:
- Rack::URLMap, to route to multiple applications inside the same process.
- Rack::CommonLogger, for creating Apache-style logfiles.
- Rack::ShowException, for catching unhandled exceptions and
presenting them in a nice and helpful way with clickable backtrace.
- Rack::File, for serving static files.
- …
All these components use the same interface, which is described in
detail in the Rack specification. You can choose to use them exactly
in the way you want.
Convenience
If you want to develop outside of existing frameworks, implement your
own ones, or develop middleware, Rack provides many helpers to create
Rack applications quickly and without doing the same web stuff all
over:
- Rack::Request, which also provides query string parsing and
multipart handling.
- Rack::Response, for convenient generation of HTTP replies and
cookie handling.
- Rack::MockRequest and Rack::MockResponse for efficient and quick
testing of Rack application without real HTTP round-trips.
rackup
rackup is a useful tool for running Rack applications, which uses the
Rack::Builder DSL to configure middleware and build up applications
easily.
rackup automatically figures out the environment it is run in, and
runs your application as FastCGI, CGI, or standalone with Mongrel or
WEBrick—all from the same configuration.
Where can I get it?
You can download Rack 0.2 here:
Alternatively, you can checkout from the development repository with:
darcs get http://chneukirchen.org/repos/rack
(Patches using “darcs send” are most welcome.)
Installing with RubyGems
A Gem of Rack is available. You can install it with:
gem install rack
I also provide a local mirror of the gems (and development snapshots)
at my site:
gem install rack --source http://chneukirchen.org/releases/gems
History
March 3rd, 2007: First public release 0.1.
May 16th, 2007: Second public release 0.2.
- HTTP Basic authentication.
- Cookie Sessions.
- Static file handler.
- Improved Rack::Request.
- Improved Rack::Response.
- Added Rack::ShowStatus, for better default error messages.
- Bug fixes in the Camping adapter.
- Removed Rails adapter, was too alpha.
Contact
Please mail bugs, suggestions and patches to
.
You are also welcome to join the #rack channel on irc.freenode.net.
Thanks to
- Michael Fellinger, for the helpful discussion, bugfixes and a better
Rack::Request interface.
- Christoffer Sawicki, for the Rails adapter.
- Tim Fletcher, for the HTTP authentication code.
- Armin Ronacher, for the logo and racktools.
- Aredridel, for bug fixing.
- Gary Wright, for proposing a better Rack::Response interface.
- Alexander Kellett for testing the Gem and reviewing the announce.
- Marcus Rückert, for help with configuring and debugging lighttpd.
- The WSGI team for the well-done and documented work they’ve done and
Rack builds up on.
Copyright
Copyright (C) 2007 Christian Neukirchen http://purl.org/net/chneukirchen
Rack is freely distributable under the terms of an MIT-style license.
Links
Rack: http://rack.rubyforge.org/
Rack’s Rubyforge project: http://rubyforge.org/projects/rack
Camping: http://camping.rubyforge.org/
Ramaze: http://ramaze.rubyforge.org/
Maveric: http://maveric.rubyforge.org/
racktools: http://lucumr.pocoo.org/trac/repos/racktools/
f1063711f228d19875a3211d71308b5c rack-0.2.0.tar.gz
fad21b5fac8790fe6bf295fefdac5816 rack-0.2.0.gem
NP: Aimee Mann—Clean Up For Christmas
Abi-Gag im PG
Mir fällt zum Abi-Gag im PG nichts ein.
Hätte man mir nicht gesagt, dass er heute sei, hätte ich ihn nicht
bemerkt.
NP: Aimee Mann—Little Bombs