{"id":458,"date":"2010-12-30T02:07:35","date_gmt":"2010-12-30T01:07:35","guid":{"rendered":"https:\/\/d-mueller.de\/blog\/?p=458"},"modified":"2010-12-30T02:07:35","modified_gmt":"2010-12-30T01:07:35","slug":"ueberdeckungsorientierte-testverfahren","status":"publish","type":"post","link":"https:\/\/d-mueller.de\/blog\/ueberdeckungsorientierte-testverfahren\/","title":{"rendered":"\u00dcberdeckungsorientierte Testverfahren"},"content":{"rendered":"<p>Unit-Tests sind ja hinreichend bekannt. Die nachfolgend vorgestellten Testverfahren sicher jedoch weniger. Deshalb gibts heut mal einen kleinen Ausflug. Ohne viel Vorgepl\u00e4nkel stelle ich verschiedene \u00fcberdeckungsorientierte Testverfahren vor.<\/p>\n<h2>Zeilen\u00fcberdeckung<\/h2>\n<p>Folgender (sinnloser) Code:<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\nfunction foo($bar)\r\n{\r\n\tif ($bar &amp;&amp; !$bar)\r\n\t\treturn true;\r\n\t\t\r\n\treturn false;\r\n}\r\n<\/pre>\n<p>Was f\u00e4llt auf? Die Funktion kann <b>nie true returnen<\/b>. Durch einen Test auf Zeilenabdeckung kann also erkannt werden, dass hier irgendwas nicht stimmt, weil die <i>return true;<\/i> &#8211; Zeile niemals erreicht wird. Allerdings (gro\u00dfes allerdings!), w\u00fcrde folgende &#8222;Umstellung&#8220; des Codes bereits zu einer 100%igen Zeilen\u00fcberdeckung f\u00fchren:<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\nfunction foo($bar)\r\n{\r\n\tif ($bar &amp;&amp; !$bar) return true;\r\n\t\t\r\n\treturn false;\r\n}\r\n<\/pre>\n<p>Klasse, oder? Einfach das <i>return true<\/i> in die selbe Zeile geklatscht und schon wird diese Zeile ausgef\u00fchrt. Auch wenn man mit dem Codesniffer argumentieren k\u00f6nnte, kann die Zeilen\u00fcberdeckung also unm\u00f6glich das gelbe vom Ei sein.<\/p>\n<h2>Anweisungs\u00fcberdeckung<\/h2>\n<div id=\"attachment_459\" style=\"width: 221px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/anweisungsueberdeckung.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-459\" src=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/anweisungsueberdeckung.png\" alt=\"Anweisungsueberdeckung\" title=\"Anweisungsueberdeckung\" width=\"211\" height=\"277\" class=\"size-full wp-image-459\" \/><\/a><p id=\"caption-attachment-459\" class=\"wp-caption-text\">Anweisungsueberdeckung<\/p><\/div>\n<p>Die Anweisungs\u00fcberdeckung l\u00f6st das Problem der Zeilen\u00fcberdeckung, indem gepr\u00fcft wird, ob alle Anweisungen im Code mindestens einmal ausgef\u00fchrt werden. So w\u00fcrde sich das <i>return true<\/i> aus dem Beispiel oben nicht mehr verstecken k\u00f6nnen, selbst wenn es in der gleichen Zeile steht &#8211; es ist und bleibt eine Anweisung, die nie ausgef\u00fchrt wird. Damit l\u00e4sst sich also schon einiges an totem Code erkennen.<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\nfunction doStuff()\r\n{\r\n\tprint &quot;Doing stuff&quot;;\r\n\treturn;\r\n\t\r\n\tveryComplexFunction();\r\n\t$foo = new Bar();\r\n\treturn $foo;\t\r\n}\r\n<\/pre>\n<p>Der Code wird immer sinnvoller, gell? Prinzip sollte aber klarwerden: Alles unterhalb des ersten returns wird nie erreicht, weswegen die letzten 3 Anweisungen in der Funktion gnadenlos durch den Anweisungs\u00fcberdeckungs-Test auffallen.<\/p>\n<p>Was ist das <b>Problem mit der Anweisungs\u00fcberdeckung?<\/b><\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\nfunction helloworld($hello)\r\n{\r\n\tif ($hello == &quot;hello&quot;)\r\n\t{\r\n\t\tprint &quot;Hello World&quot;;\r\n\t\treturn true;\r\n\t}\r\n}\r\n<\/pre>\n<p>Bei obigem Code ist die Anweisungs\u00fcberdeckung zufrieden: Es k\u00f6nnen alle Anweisungen erreicht werden. Nur: Was ist, wenn der Parameter <i>$hello<\/i> nicht &#8222;hello&#8220; ist? Also: Was ist mit dem <b>leeren else-Zweig<\/b>?<\/p>\n<h2>Zweig\u00fcberdeckung<\/h2>\n<div id=\"attachment_460\" style=\"width: 228px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/zweigueberdeckung.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-460\" src=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/zweigueberdeckung.png\" alt=\"Zweigueberdeckung\" title=\"Zweigueberdeckung\" width=\"218\" height=\"272\" class=\"size-full wp-image-460\" \/><\/a><p id=\"caption-attachment-460\" class=\"wp-caption-text\">Zweigueberdeckung<\/p><\/div>\n<p>Die Zweig\u00fcberdeckung l\u00f6st dieses Problem: <b>Alle Zweige des Programms m\u00fcssen durchlaufen werden.<\/b> Hei\u00dft: Zu jedem &#8222;if&#8220; gibt es auch ein else &#8211; selbst wenn es im Code nicht explizit angegeben ist. Damit subsumiert die Zweig\u00fcberdeckung die Anweisungs\u00fcberdeckung. Dabei kann die Zweig\u00fcberdeckung ziemlich aufw\u00e4ndig zu testen sein, denn <i>if&#8217;s<\/i> in Schleifen werden z.B. schnell sehr aufw\u00e4ndig zu testen und erfordern oft das <b>Einschleusen von boolschen Variablen<\/b>, um das Abbiegen in einen gewissen Zweig zu erzwingen.<\/p>\n<h2>Pfad\u00fcberdeckung<\/h2>\n<p>Noch nicht komplex genug? Kein Problem! Die Pfad\u00fcberdeckung stellt wohl die Kr\u00f6nung dar. Es muss <b>jeder m\u00f6gliche Pfad durch das Programm von Anfang bis Ende begangen werden<\/b>. <\/p>\n<div id=\"attachment_461\" style=\"width: 310px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/pfadueberdeckung.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-461\" src=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/pfadueberdeckung-300x181.png\" alt=\"Pfadueberdeckung\" title=\"Pfadueberdeckung\" width=\"300\" height=\"181\" class=\"size-medium wp-image-461\" srcset=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/pfadueberdeckung-300x181.png 300w, https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/pfadueberdeckung-1024x620.png 1024w, https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/pfadueberdeckung.png 1188w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-461\" class=\"wp-caption-text\">Pfadueberdeckung<\/p><\/div>\n<p>Das Bild zeigt, wieviele Varianten es gibt, allein eine einzige Funktion zu durchlaufen (Schleifen sind der Tod!). <\/p>\n<h2>That&#8217;s it<\/h2>\n<p>In der Praxis muss man ohnehin selbst entscheiden, welchen Aufwand man betreiben m\u00f6chte. Finde es aber ganz angenehm, die verschiedenen Verfahren immer im Hinterkopf zu haben.<\/p>\n<p><b>Bildquelle<\/b> der ersten beiden Bilder: <a href=\"http:\/\/de.wikipedia.org\/wiki\/Kontrollflussorientierte_Testverfahren\">Wikipedia: Kontrollflussorientierte Testverfahren<\/a> (ohnehin sehr empfehlenswerter Artikel), <b>Bildquelle<\/b> des letzten Bildes: Script des gesch\u00e4tzten Profs <a href=\"http:\/\/www.fbi.h-da.de\/organisation\/personen\/hahn-ralf.html\">Ralf Hahn<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Unit-Tests sind ja hinreichend bekannt. Die nachfolgend vorgestellten Testverfahren sicher jedoch weniger. Deshalb gibts heut mal einen kleinen Ausflug. Ohne viel Vorgepl\u00e4nkel stelle ich verschiedene \u00fcberdeckungsorientierte Testverfahren vor. Zeilen\u00fcberdeckung Folgender (sinnloser) Code: function foo($bar) { if ($bar &amp;&amp; !$bar) return &hellip; <a href=\"https:\/\/d-mueller.de\/blog\/ueberdeckungsorientierte-testverfahren\/\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,5,3],"tags":[],"class_list":["post-458","post","type-post","status-publish","format-standard","hentry","category-php","category-software-engineering","category-webdev"],"_links":{"self":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts\/458","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/comments?post=458"}],"version-history":[{"count":0,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts\/458\/revisions"}],"wp:attachment":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/media?parent=458"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/categories?post=458"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/tags?post=458"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}