{"id":20963,"date":"2014-09-19T14:58:03","date_gmt":"2014-09-19T13:58:03","guid":{"rendered":"https:\/\/www.inovex.de\/\/?p=53"},"modified":"2014-09-19T14:58:03","modified_gmt":"2014-09-19T13:58:03","slug":"fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure","status":"publish","type":"post","link":"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/","title":{"rendered":"Midje als alternatives Testframework f\u00fcr Clojure: Fakten, Fakten, Fakten!"},"content":{"rendered":"<p>Midges sind <a href=\"http:\/\/en.wikipedia.org\/wiki\/Highland_midge\" target=\"_blank\" rel=\"noopener\">kleine aber unangenehme Zeitgenossen<\/a>, die einen Aufenthalt in den schottischen Highlands ohne die richtige Vorbereitung zur H\u00f6lle machen k\u00f6nnen. Das <strong>Clojure Testframework Midje<\/strong> hat mit diesen M\u00fccken zum Gl\u00fcck nur den Namen gemein. Im Gegensatz zu ihnen macht es das Entwicklerleben nicht schwerer, sondern das Testen von Clojure-Programmen auch ohne gro\u00dfe und aufwendige Vorbereitung und Einarbeitung sehr angenehm.<!--more--><\/p>\n<p>Midje (sprich [m\u026ad\u0292]) ist ein Test-Framework f\u00fcr Clojure und damit eine Alternative zu clojure.test. Gro\u00dfe St\u00e4rken von Midje sind die bessere Lesbarkeit von Tests und das einfache Stubben und Mocken von Funktionen. Die Tests werden in einer Form geschrieben, die auch in Clojure-B\u00fcchern wie zum Beispiel <a href=\"http:\/\/www.amazon.de\/Joy-Clojure-Michael-Fogus\/dp\/1617291412\/\" target=\"_blank\" rel=\"noopener\">The Joy of Clojure<\/a> f\u00fcr Beispiele verwendet wird. Eine sehr einfache Testerwartung sieht etwa so aus:<\/p>\n<pre class=\"lang:default decode:true \">(+ 1 1) =&gt; 2<\/pre>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_79_2 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\"><p class=\"ez-toc-title\" style=\"cursor:inherit\"><\/p>\n<\/div><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#Facts-und-Checkables\" >Facts und Checkables<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#Listing-1-Facts\" >Listing 1: Facts<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#Listing-2-Future-Fact\" >Listing 2: Future Fact<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#Listing-3-Midje-Projekt-Dateistruktur\" >Listing 3: Midje Projekt Dateistruktur<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#Listing-4-Grundstruktur-eines-Midje-Test-Namespaces\" >Listing 4: Grundstruktur eines Midje Test Namespaces<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#Listing-5-Testergebnis\" >Listing 5: Testergebnis<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#Listing-6-anything-Checker\" >Listing 6: anything Checker<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#Listing-7-contains-Checker\" >Listing 7: contains Checker<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#Listing-8-Eigener-Checker\" >Listing 8: Eigener Checker<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#Listing-9-Stubbing-mit-der-provided-Form\" >Listing 9: Stubbing mit der provided Form<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#Listing-10-Aufrufhaeufigkeiten-beim-Mocken\" >Listing 10: Aufrufh\u00e4ufigkeiten beim Mocken<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#Fazit\" >Fazit<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"Facts-und-Checkables\"><\/span>Facts und Checkables<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Tests werden anhand von Fakten zusammengefasst und strukturiert. Das Makro fact bzw. facts kann optional um einen auch bei Clojure-Funktionen \u00fcblichen Docstring zur genaueren Erl\u00e4uterung des Tests erg\u00e4nzt werden. Die Verwendung dieser Dokumentation hat sich als sehr sinnvoll f\u00fcr den schnelleren \u00dcberblick \u00fcber eine Testsuite erwiesen. Facts k\u00f6nnen beliebig verschachtelt werden, wobei facts lediglich ein Synonym f\u00fcr fact ist, um die Lesbarkeit zu verbessern. (Listing 1)<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Listing-1-Facts\"><\/span>Listing 1: Facts<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre class=\"lang:default decode:true \">(facts \"about `+`\"\n\n(fact \"1 plus 1 equals 2\"\n\n(+ 1 1) =&gt; 2)\n\n(fact \"adding negative numbers results in a negative number\"\n\n(+ -1 -1) =&gt; -2))<\/pre>\n<p>Facts bestehen aus einem oder mehreren <em>Checkables<\/em>. Ein Checkable besteht aus einem Pfeil (=&gt;) und einer rechten und linken Seite. Die linke Seite enth\u00e4lt die auszuf\u00fchrende Funktion mit ihren Argumenten, die rechte Seite das erwartete Ergebnis. Statt =&gt; kann auch =not=&gt; verwendet werden, um direkt die Ungleichheit der beiden Seiten des Checkables zu pr\u00fcfen. In Listing 1 befinden sich auf der rechten Seite der Checkables jeweils einfache Werte. Statt einfacher Werte lassen sich \u00fcber <em>Checker<\/em> auch komplexere Bedingungen pr\u00fcfen. Dazu sp\u00e4ter mehr. Wenn Facts zur Spezifikation von gewolltem Softwareverhalten verwendet werden, werden diese wie im TDD \u00fcblich vor dem eigentlichen Verhalten implementiert. Um einen Fact f\u00fcr ein sp\u00e4ter gew\u00fcnschtes Verhalten zu implementieren, ohne die Tests fehlschlagen zu lassen, kann das Makro future-fact verwendet werden. Die Checkables in einem future-fact werden bei der Ausf\u00fchrung der Tests nicht evaluiert. Midje gibt lediglich ein WORK TO DO aus. (Listing 2)<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Listing-2-Future-Fact\"><\/span>Listing 2: Future Fact<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre class=\"lang:default decode:true \">(future-fact \"about a new fancy function\" (fact \"it returns fancy\"\n\n(fancy-function) =&gt; \"fancy\"))<\/pre>\n<p>Midje bringt ein eigenes Leiningen-Plugin zum Erzeugen der passenden Ordner- und Dateistruktur sowie zum Ausf\u00fchren der Tests mit. Dieses muss einmal in der Datei ~\/.lein\/profiles.clj registriert werden:<\/p>\n<pre class=\"lang:default decode:true \">{:user {:plugins [[lein-midje \"3.1.3\"]]}}<\/pre>\n<p>Ein neues Projekt mit Unterst\u00fctzung f\u00fcr Midje kann dann per lein new midje projektname angelegt werden. Das Leiningen-Plugin erzeugt automatisch die in Listing 3 dargestellte Dateistruktur und f\u00fcllt den Test-Namespace mit einem kleinen Beispiel.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Listing-3-Midje-Projekt-Dateistruktur\"><\/span>Listing 3: Midje Projekt Dateistruktur<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre class=\"lang:default decode:true \">$ lein new midje midje-demo\n\n=&amp;gt;\n\n|____project.clj\n\n|____README.md\n\n|____src\n\n| |____midje_demo\n\n| | |____core.clj\n\n|____test\n\n| |____midje_demo\n\n| | |____t_core.clj<\/pre>\n<p>Nat\u00fcrlich kann diese Struktur auch manuell in ein bereits bestehendes Projekt eingepflegt werden. Ein Midje Test Namespace verwendet zumindest den getesteten Namespace und midje.sweet, in dem alle relevanten Funktionen und Makros von Midje deklariert sind. (Listing 4)<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Listing-4-Grundstruktur-eines-Midje-Test-Namespaces\"><\/span>Listing 4: Grundstruktur eines Midje Test Namespaces<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre class=\"lang:default decode:true \">$ lein new midje midje-demo\n\n=&amp;gt;\n\n|____project.clj\n\n|____README.md\n\n|____src\n\n| |____midje_demo\n\n| | |____core.clj\n\n|____test\n\n| |____midje_demo\n\n| | |____t_core.clj<\/pre>\n<p>Im Projektverzeichnis k\u00f6nnen alle vorhandenen Midje Tests per lein midje ausgef\u00fchrt werden. Dieser Aufruf hat den Nachteil, dass das Starten der JVM und der Clojure-Laufzeitumgebung etwas Zeit in Anspruch nimmt und man so relativ lange auf die Testergebnisse warten muss.<\/p>\n<p>Startet man die Tests hingegen mit lein midje :autotest, wird f\u00fcr den ersten Start zwar genau so viel Zeit ben\u00f6tigt, aber Midje bleibt dann aktiv und erkennt \u00c4nderungen an den Tests oder den getesteten Namespaces und f\u00fchrt diese bei jeder \u00c4nderung automatisch erneut in der anfangs gestarteten Laufzeitumgebung aus. Wenn man die Tests aus Listing 1 ausf\u00fchrt, erh\u00e4lt man die Ausgabe in Listing 5 unter \u201eTestausf\u00fchrung 1\u201c. Hier zeigt sich auch der Vorteil der Verwendung eines Docstrings f\u00fcr die Fakten. Das Testprotokoll ist dann gut lesbar. F\u00fcr die zweite Testausf\u00fchrung in Listing 5 wurde der zweite Fakt absichtlich so angepasst, dass er fehlschl\u00e4gt, um die entsprechende Ausgabe zu demonstrieren. (Die Erwartung wurde von -2 auf 2 ge\u00e4ndert.)<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Listing-5-Testergebnis\"><\/span>Listing 5: Testergebnis<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre class=\"lang:default decode:true \">;; Testausf\u00fchrung 1\n\n$ lein midje\n\n= Namespace midje_demo.t-core\n\nChecking about `+`\n\nChecking 1 plus 1 equals 2\n\nChecking adding negative numbers results in a negative number\n\nAll checks (2) succeeded.\n\n;; Testausf\u00fchrung 2 mit absichtlich fehlerhaftem Test\n\n$ lein midje\n\n= Namespace midje_demo.t-core\n\nChecking about `+`\n\nChecking 1 plus 1 equals 2\n\nChecking adding negative numbers results in a negative number\n\nFAIL \"about `+` - adding negative numbers results in a negative number\" at ...\n\nExpected: 2\n\nActual: -2\n\nFAILURE: 1 check failed. (But 1 succeeded.)<\/pre>\n<p>Auf der rechten Seite eines Checkables k\u00f6nnen statt einfachen Werten, die gegen das Funktionsergebnis verglichen werden, auch von Midje vordefinierte Funktionen, \u201eCheckers\u201c, verwendet werden. Midje ruft den Checker mit dem Ergebnis der Funktion auf der linken Seite des Checkables als Argument auf. Midje bringt bereits eine gro\u00dfe Anzahl von Checkern mit. Im Folgenden betrachten wir einige davon exemplarisch. Weitere Checker sind im Midje-Wiki[3] dokumentiert.<\/p>\n<p><strong>truthy, falsey<\/strong>: Diese Checker k\u00f6nnen verwendet werden, wenn das Ergebnis einer Funktion true oder nicht nil bzw. false oder nil sein soll, ohne dass es auf die genaue Auspr\u00e4gung des Ergebnisses ankommt.<\/p>\n<p>anything, irrelevant In manchen F\u00e4llen ist ein Test so aufgebaut, dass das Ergebnis der Funktion f\u00fcr den Test nicht relevant ist. \u00dcblicherweise trifft das bei Funktionen mit Seiteneffekten (z.B. Datenbank-Inserts) zu. Dann kann die Funktion ausgef\u00fchrt werden, ohne dass der R\u00fcckgabewert Auswirkungen auf den Test hat (Listing 6). Ein weiteres Anwendungsgebiet ist die Verwendung von Prerequisites, die wir sp\u00e4ter im Artikel betrachten.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Listing-6-anything-Checker\"><\/span>Listing 6: anything Checker<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre class=\"lang:default decode:true \">(facts \"about db inserts\"\n\n(fact \"it finds the entry after an insert\" (insert-name 1 \"the inserted name\") =&gt; anything (find-name 1) =&gt; \"the inserted name\"))<\/pre>\n<p><strong>throws<\/strong>: Der throws-Checker verlangt, dass ein Funktionsaufruf eine Exception wirft. (fact (throwing-function) =&gt; (throws Exception)) Auch das Pr\u00fcfen der Exception-Message ist m\u00f6glich. (fact (throwing-function) =&gt; (throws Exception &#8222;foo&#8220;)) Die Exception Message kann auch gegen einen regul\u00e4ren Ausdruck gepr\u00fcft werden. (fact (throwing-function) =&gt; (throws Exception #&#8220;(foo|bar)&#8220;))<\/p>\n<p><strong>contains<\/strong>: Dieser Checker kann auf Sequences oder Maps angewendet werden. Er pr\u00fcft, ob sich ein bestimmter Wert bzw. ein Schl\u00fcssel-Wert-Paar darin befindet. Es k\u00f6nnen beliebig viele Werte bzw. Paare als Argument \u00fcbergeben werden. Au\u00dferdem k\u00f6nnen statt konkreten Werten auch Funktionen verwendet werden, die Eigenschaften der Werte pr\u00fcfen. (Listing 7)<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Listing-7-contains-Checker\"><\/span>Listing 7: contains Checker<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre class=\"lang:default decode:true \">(facts \"about my sequence\"\n\n(fact \"it contains the value 5\"\n\n'(1 2 3 4 5 6) =&gt; (contains 5))\n\n(fact \"it contains the values 2 and 3\"\n\n'(1 2 3 4 5 6) =&gt; (contains 2 3))\n\n(fact \"it contains an odd number followed by an even number\"\n\n'(1 2 3 4 5 6) =&gt; (contains odd? even?)))\n\n(facts \"about my map\"\n\n(fact \"the value of x is 1\"\n\n{:x 1 :y 2} =&gt; (contains {:x 1}))\n\n(fact \"the value of y is even\"\n\n{:x 1 :y 2} =&gt; (contains {:y even?})))<\/pre>\n<p>Man kann eine Checker-Funktion auch selbst implementieren. Dazu schreibt man eine Higher-Order-Function, die eine Funktion zur\u00fcckgibt, die als erstes Argument das zu pr\u00fcfende Funktionsergebnis erwartet. (Listing 8)<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Listing-8-Eigener-Checker\"><\/span>Listing 8: Eigener Checker<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre class=\"lang:default decode:true \">(defn each-element-is-one-of [expected-elements]\n\n(fn [actual]\n\n(every? (set expected-elements) actual)))\n\n(fact \"each element is one of 1-10\"\n\n'(1 2 3 4 5 6) =&gt; (each-element-is-one-of (range 1 11)))\n\n<\/pre>\n<p>Stubs und Mocks sind aus der objektorientierten Welt bekannt. Sie werden dort verwendet, um ein Objekt unabh\u00e4ngig von seinen Kollaborateuren testen zu k\u00f6nnen. In der funktionalen Welt gibt es zwar keine kollaborierenden Objekte aber andere Funktionen, die von der zu testenden Funktion aufgerufen werden. Um die zu testende Funktion unabh\u00e4ngig zu machen, bietet Midje die provided Form. Unter Verwendung von provided lassen sich einerseits vorgefertigte Ergebnisse aus einer Funktion (Prerequisites) zur\u00fcckgeben und andererseits die Aufrufe der Funktion protokollieren und abpr\u00fcfen. Nehmen wir an, wir wollen eine Funktion authenticate implementieren, die anhand ihrer Argumente einen User in der Datenbank sucht und dann pr\u00fcft, ob dessen Passwort korrekt angegeben wurde. Ist das Passwort korrekt, wird der User zur\u00fcckgegeben, ansonsten nil. Wollen wir diese Funktion ohne Datenbankanbindung testen, so m\u00fcssen wir die Datenbanksuche so stubben, dass ein passender Testuser zur\u00fcckgegeben wird. Dazu geben wir zus\u00e4tzlich zum eigentlichen Checkable eine provided Form an, in der wir den gew\u00fcnschten R\u00fcckgabewert der gestubbten Funktion f\u00fcr unseren Test spezifizieren. (Listing 9)<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Listing-9-Stubbing-mit-der-provided-Form\"><\/span>Listing 9: Stubbing mit der provided Form<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre class=\"lang:default decode:true \">(defn find-user [username]\n\n;; Code, der den User anhand des Namens in der DB sucht und zur\u00fcckgibt\n\n)\n\n(defn authenticate [username password]\n\n(let [user (find-user username)]\n\n(if (= (:password user) password)\n\nuser)))\n\n(fact \"it authenticates a user with a valid password\"\n\n(authenticate \"&gt;\" \"12345\") =&gt; truthy\n\n(provided\n\n(find-user \"&gt;\") =&gt; {:name \"&gt;\" :password \"12345\"}))<\/pre>\n<p>Gleichzeitig kann man die provided Form auch zum Mocken verwenden. Der Test in Listing 9 w\u00fcrde auch fehlschlagen, wenn authenticate nicht find-user mit dem in der provided Form angegebenen Argument \u2013 dem Usernamen &gt; \u2013 aufruft. Ist f\u00fcr das Mocken auch die Aufrufh\u00e4ufgkeit einer Funktion interessant, kann diese Erwartung ebenfalls erg\u00e4nzt werden. Im Beispiel soll second-function beim Aufruf von first-function f\u00fcnf Mal, aber third-function nie ausgef\u00fchrt werden. Die R\u00fcckgabewerte der aufgerufenen Funktionen sind f\u00fcr diesen Test nicht relevant. (Listing 10)<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Listing-10-Aufrufhaeufigkeiten-beim-Mocken\"><\/span>Listing 10: Aufrufh\u00e4ufigkeiten beim Mocken<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre class=\"lang:default decode:true \">(fact \"it calls the second function 5 times with argument `foo`\" (first-function) =&gt; irrelevant (provided (second-function \"foo\") =&gt; irrelevant :times 5))\n\n(fact \"it never calls the third function with any argument\" (first-function) =&gt; irrelevant (provided (third-function anything) =&gt; irrelevant :times 0))<\/pre>\n<h2><span class=\"ez-toc-section\" id=\"Fazit\"><\/span>Fazit<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Midje ist ein m\u00e4chtiges und zugleich sehr einsteigerfreundliches Framework zum Implementieren von Tests in Clojure. Die damit entstehenden Tests sind leichter zu lesen als die Pendants in clojure.test, was nicht zuletzt der Pfeil-Schreibweise (=&gt;) und den einfachen Stubbing- und Mockingm\u00f6glichkeiten zu verdanken ist, die in clojure.test nur durch das Schreiben eigener Makros oder das Einbinden weiterer Bibliotheken zu erreichen sind. Die gute Unterst\u00fctzung durch das passende Leiningen-Plugin rundet das positive Gesamtbild weiter ab. Midje bietet noch eine Reihe weiterer M\u00f6glichkeiten um Tests zu implementieren. Diese fortgeschrittenen Elemente w\u00fcrden den Rahmen dieses Einf\u00fchrungsartikels sprengen. Deshalb sei auf das sehr ausf\u00fchrliche Wiki auf den <a href=\"https:\/\/github.com\/marick\/Midje\/wiki\" target=\"_blank\" rel=\"noopener\">GitHub-Seiten von Midje<\/a> verwiesen.<\/p>\n<p><em><\/p>\n<p><\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Midges sind kleine aber unangenehme Zeitgenossen, die einen Aufenthalt in den schottischen Highlands ohne die richtige Vorbereitung zur H\u00f6lle machen k\u00f6nnen. Das Clojure Testframework Midje hat mit diesen M\u00fccken zum Gl\u00fcck nur den Namen gemein. Im Gegensatz zu ihnen macht es das Entwicklerleben nicht schwerer, sondern das Testen von Clojure-Programmen auch ohne gro\u00dfe und aufwendige [&hellip;]<\/p>\n","protected":false},"author":15,"featured_media":13118,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"ep_exclude_from_search":false,"footnotes":""},"tags":[510,68,69],"service":[],"coauthors":[{"id":15,"display_name":"Tobias Bayer","user_nicename":"tbayer"}],"class_list":["post-20963","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-apps-2","tag-backend","tag-digital-quality"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Midje als alternatives Testframework f\u00fcr Clojure<\/title>\n<meta name=\"description\" content=\"Das Clojure Testframework Midje macht das Testen von Clojure-Programmen auch ohne gro\u00dfe und aufwendige Vorbereitung und Einarbeitung sehr angenehm.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Midje als alternatives Testframework f\u00fcr Clojure\" \/>\n<meta property=\"og:description\" content=\"Das Clojure Testframework Midje macht das Testen von Clojure-Programmen auch ohne gro\u00dfe und aufwendige Vorbereitung und Einarbeitung sehr angenehm.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/\" \/>\n<meta property=\"og:site_name\" content=\"inovex GmbH\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/inovexde\" \/>\n<meta property=\"article:published_time\" content=\"2014-09-19T13:58:03+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2014\/09\/clojure-midje.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"1080\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Tobias Bayer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2014\/09\/clojure-midje-1024x576.png\" \/>\n<meta name=\"twitter:creator\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:site\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Tobias Bayer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"8\u00a0Minuten\" \/>\n\t<meta name=\"twitter:label3\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data3\" content=\"Tobias Bayer\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/\"},\"author\":{\"name\":\"Tobias Bayer\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/b6732bacef2fddaa8e9003b627963795\"},\"headline\":\"Midje als alternatives Testframework f\u00fcr Clojure: Fakten, Fakten, Fakten!\",\"datePublished\":\"2014-09-19T13:58:03+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/\"},\"wordCount\":1353,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2014\/09\/clojure-midje.png\",\"keywords\":[\"Apps\",\"Backend\",\"Digital Quality\"],\"articleSection\":[\"Applications\",\"General\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/\",\"url\":\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/\",\"name\":\"Midje als alternatives Testframework f\u00fcr Clojure\",\"isPartOf\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2014\/09\/clojure-midje.png\",\"datePublished\":\"2014-09-19T13:58:03+00:00\",\"description\":\"Das Clojure Testframework Midje macht das Testen von Clojure-Programmen auch ohne gro\u00dfe und aufwendige Vorbereitung und Einarbeitung sehr angenehm.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#primaryimage\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2014\/09\/clojure-midje.png\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2014\/09\/clojure-midje.png\",\"width\":1920,\"height\":1080,\"caption\":\"Midje test framework Headerbild\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.inovex.de\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Midje als alternatives Testframework f\u00fcr Clojure: Fakten, Fakten, Fakten!\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.inovex.de\/de\/#website\",\"url\":\"https:\/\/www.inovex.de\/de\/\",\"name\":\"inovex GmbH\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.inovex.de\/de\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\",\"name\":\"inovex GmbH\",\"url\":\"https:\/\/www.inovex.de\/de\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png\",\"width\":1921,\"height\":1081,\"caption\":\"inovex GmbH\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/inovexde\",\"https:\/\/x.com\/inovexgmbh\",\"https:\/\/www.instagram.com\/inovexlife\/\",\"https:\/\/www.linkedin.com\/company\/inovex\",\"https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/b6732bacef2fddaa8e9003b627963795\",\"name\":\"Tobias Bayer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/image\/d4fcf53ee2711d02dc6ca848de636ef5\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/43494845307c31f179bd93194dc205bbc128f22a2395b729ff319148c94acdbe?s=96&d=retro&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/43494845307c31f179bd93194dc205bbc128f22a2395b729ff319148c94acdbe?s=96&d=retro&r=g\",\"caption\":\"Tobias Bayer\"},\"url\":\"https:\/\/www.inovex.de\/de\/blog\/author\/tbayer\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Midje als alternatives Testframework f\u00fcr Clojure","description":"Das Clojure Testframework Midje macht das Testen von Clojure-Programmen auch ohne gro\u00dfe und aufwendige Vorbereitung und Einarbeitung sehr angenehm.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/","og_locale":"de_DE","og_type":"article","og_title":"Midje als alternatives Testframework f\u00fcr Clojure","og_description":"Das Clojure Testframework Midje macht das Testen von Clojure-Programmen auch ohne gro\u00dfe und aufwendige Vorbereitung und Einarbeitung sehr angenehm.","og_url":"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/","og_site_name":"inovex GmbH","article_publisher":"https:\/\/www.facebook.com\/inovexde","article_published_time":"2014-09-19T13:58:03+00:00","og_image":[{"width":1920,"height":1080,"url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2014\/09\/clojure-midje.png","type":"image\/png"}],"author":"Tobias Bayer","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.inovex.de\/wp-content\/uploads\/2014\/09\/clojure-midje-1024x576.png","twitter_creator":"@inovexgmbh","twitter_site":"@inovexgmbh","twitter_misc":{"Verfasst von":"Tobias Bayer","Gesch\u00e4tzte Lesezeit":"8\u00a0Minuten","Written by":"Tobias Bayer"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#article","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/"},"author":{"name":"Tobias Bayer","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/b6732bacef2fddaa8e9003b627963795"},"headline":"Midje als alternatives Testframework f\u00fcr Clojure: Fakten, Fakten, Fakten!","datePublished":"2014-09-19T13:58:03+00:00","mainEntityOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/"},"wordCount":1353,"commentCount":0,"publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2014\/09\/clojure-midje.png","keywords":["Apps","Backend","Digital Quality"],"articleSection":["Applications","General"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/","url":"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/","name":"Midje als alternatives Testframework f\u00fcr Clojure","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#primaryimage"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2014\/09\/clojure-midje.png","datePublished":"2014-09-19T13:58:03+00:00","description":"Das Clojure Testframework Midje macht das Testen von Clojure-Programmen auch ohne gro\u00dfe und aufwendige Vorbereitung und Einarbeitung sehr angenehm.","breadcrumb":{"@id":"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#primaryimage","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2014\/09\/clojure-midje.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2014\/09\/clojure-midje.png","width":1920,"height":1080,"caption":"Midje test framework Headerbild"},{"@type":"BreadcrumbList","@id":"https:\/\/www.inovex.de\/de\/blog\/fakten-fakten-fakten-midje-als-alternatives-testframework-fuer-clojure\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.inovex.de\/de\/"},{"@type":"ListItem","position":2,"name":"Midje als alternatives Testframework f\u00fcr Clojure: Fakten, Fakten, Fakten!"}]},{"@type":"WebSite","@id":"https:\/\/www.inovex.de\/de\/#website","url":"https:\/\/www.inovex.de\/de\/","name":"inovex GmbH","description":"","publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.inovex.de\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/www.inovex.de\/de\/#organization","name":"inovex GmbH","url":"https:\/\/www.inovex.de\/de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","width":1921,"height":1081,"caption":"inovex GmbH"},"image":{"@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/inovexde","https:\/\/x.com\/inovexgmbh","https:\/\/www.instagram.com\/inovexlife\/","https:\/\/www.linkedin.com\/company\/inovex","https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ"]},{"@type":"Person","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/b6732bacef2fddaa8e9003b627963795","name":"Tobias Bayer","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/image\/d4fcf53ee2711d02dc6ca848de636ef5","url":"https:\/\/secure.gravatar.com\/avatar\/43494845307c31f179bd93194dc205bbc128f22a2395b729ff319148c94acdbe?s=96&d=retro&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/43494845307c31f179bd93194dc205bbc128f22a2395b729ff319148c94acdbe?s=96&d=retro&r=g","caption":"Tobias Bayer"},"url":"https:\/\/www.inovex.de\/de\/blog\/author\/tbayer\/"}]}},"_links":{"self":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/20963","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/comments?post=20963"}],"version-history":[{"count":0,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/20963\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media\/13118"}],"wp:attachment":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media?parent=20963"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/tags?post=20963"},{"taxonomy":"service","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/service?post=20963"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/coauthors?post=20963"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}