{"id":47,"date":"2015-03-06T10:45:42","date_gmt":"2015-03-06T08:45:42","guid":{"rendered":"http:\/\/invidit.de\/blog\/?p=47"},"modified":"2015-07-04T14:38:02","modified_gmt":"2015-07-04T12:38:02","slug":"unit-tests-in-c-schreiben","status":"publish","type":"post","link":"https:\/\/invidit.de\/blog\/unit-tests-in-c-schreiben\/","title":{"rendered":"Unit Tests in C# schreiben"},"content":{"rendered":"<p>Hallo Spa\u00df-Coder.<\/p>\n<p>Unit Tests sind eine coole Sache. Warum? Weil ich vor meinen \u00c4nderungen am Code leicht pr\u00fcfen kann, ob alles wie beabsichtigt funktioniert. Dann mache ich meine \u00c4nderungen und kann anschlie\u00dfend wieder pr\u00fcfen, ob immer noch alles funktioniert. Damit sinkt f\u00fcr mich die Gefahr, bei Code\u00e4nderungen bestehende Funktion kaputt zu machen.<\/p>\n<p>Es muss nicht zwingend testgetrieben entwickelt werden. Selbst sp\u00e4ter Unit Tests hinzuzuf\u00fcgen kann hilfreich sein<\/p>\n<ul>\n<li>um den Code zu verstehen und<\/li>\n<li>um meine \u00c4nderung abzusichern (inhaltliche oder strukturelle \u00c4nderung).<\/li>\n<\/ul>\n<p>In verschiedenen Programmiersprachen werden mittlerweile Unit Test Framework bereitgestellt, welche das Schreiben und Ausf\u00fchren von Unit Test unterst\u00fctzen. F\u00fcr .Net sind Microsoft UnitTesting und NUnit bekannte Frameworks. Auf letzteres werden wir hier nicht eingehen, mehr Infos dazu sind unter <a title=\"staratnight.de\/blog\" href=\"http:\/\/staratnight.de\/blog\/nunit-tests-in-visual-studio-express-verwenden\/\" target=\"_blank\">staratnight.de\/blog<\/a> zu finden.<\/p>\n<p>Machen wir ein kleines Beispiel zu UnitTests mit Microsoft UnitTesting und nutzen dazu diese einfache Klasse mit einer Methode zur Berechnung der ersten n Fibonacci Zahlen nach <em>fn = fn-1 + fn-2 <\/em>f\u00fcr<em> n &gt; 2 <\/em>mit<em> f1 = f2 = 1<\/em>.<\/p>\n<pre class=\"lang:c# decode:true\" title=\"Fibonacci\">using System.Collections.Generic;\r\n\r\nnamespace Fibonacci\r\n{\r\n    public class Fibonacci\r\n    {\r\n        public List&lt;int&gt; GetFirstNNumbers(int n)\r\n        {\r\n            List&lt;int&gt; fibonacciNumbers = new List&lt;int&gt;();\r\n\r\n            int firstNumber = 1;\r\n            int secondNumber = 1;          \r\n            fibonacciNumbers.Add(firstNumber);\r\n            fibonacciNumbers.Add(secondNumber);\r\n\r\n            for (int i = 2; i &lt; n; i++)\r\n            {\r\n                fibonacciNumbers.Add(fibonacciNumbers[i - 2] + fibonacciNumbers[i - 2]);\r\n            }\r\n            return fibonacciNumbers;\r\n        }        \r\n    }\r\n}<\/pre>\n<p>Wenn wir diesen Code vorfinden und gerne \u00e4ndern m\u00f6chten, ohne dabei die Funktion kaputt zu machen, k\u00f6nnen wir zun\u00e4chst Unit Test daf\u00fcr schreiben. Daf\u00fcr f\u00fcge ich der Projekt Solution ein neues <strong>Unit Test Projekt<\/strong> hinzu und erg\u00e4nze dort den Verweis auf das zu testende Projekt <em>Fibonacci<\/em>. Dies sind dann wie folgt aus:<\/p>\n<p><a href=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/SolutionExploererFibonacciWithUnitTest.png\"><img decoding=\"async\" loading=\"lazy\" class=\" size-medium wp-image-75 aligncenter\" src=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/SolutionExploererFibonacciWithUnitTest-300x213.png\" alt=\"SolutionExplorerFibonacciWithUnitTest\" width=\"300\" height=\"213\" srcset=\"https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/SolutionExploererFibonacciWithUnitTest-300x213.png 300w, https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/SolutionExploererFibonacciWithUnitTest.png 350w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>F\u00fcr die Namensgebung des Projekts wird einfach ein &#8222;.Test&#8220; an den Projektnamen des zu testenden Projekts angeh\u00e4ngt. Visual Studio erzeugt eine Testklasse mit der Grundstruktur eines Unit Tests als Vorlage:<\/p>\n<pre class=\"lang:c# decode:true  \" title=\"Leerer Unit Test\">using System;\r\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\r\n\r\nnamespace Fibonacci.Test\r\n{\r\n    [TestClass]\r\n    public class UnitTest1\r\n    {\r\n        [TestMethod]\r\n        public void TestMethod1()\r\n        {\r\n        }\r\n    }\r\n}<\/pre>\n<p>Zun\u00e4chst wird der Klassenname an die zu testende Klasse angepasst: aus <em>UnitTest1<\/em> wird damit <em>FibonacciTests<\/em>. Wichtig sind die beiden Attribute<strong> [TestClass]<\/strong> und<strong> [TestMethod]<\/strong>. Daran erkennt das Testframework, was bei der Ausf\u00fchrung der Tests zu ber\u00fccksichtigen ist.<\/p>\n<p>Was wollen wir zuerst pr\u00fcfen? Beginnen wir mit einfachen F\u00e4llen und testen die ersten 2 Zahlen auf Richtigkeit. F\u00fcr jeden Test schreiben wir eine Testmethode mit dem folgenden Aufbau:<\/p>\n<ul>\n<li>Vorbereiten<\/li>\n<li>Durchf\u00fchren<\/li>\n<li>Pr\u00fcfen<\/li>\n<\/ul>\n<p>Ich beginne jetzt bewusst mit dem Test f\u00fcr n = 2, weil ich wei\u00df, dass n = 1 nicht funktioniert, was wir sp\u00e4tzer erg\u00e4nzen k\u00f6nnen.<\/p>\n<pre class=\"lang:default decode:true\" title=\"Test GetFirst2Numbers\">        [TestMethod]\r\n        public void First2NumbersAreCorrect()\r\n        {\r\n            Fibonacci sut = new Fibonacci();\r\n\r\n            var numbers = sut.GetFirstNNumbers(2);\r\n\r\n            Assert.AreEqual(1, numbers[0]);\r\n            Assert.AreEqual(1, numbers[1]);\r\n        }\r\n    }<\/pre>\n<p>Der Methodenname sollte sprechend gew\u00e4hlt werden, damit die Absicht des Tests direkt klar wird.<\/p>\n<p>Die Abk\u00fcrzung <em>sut<\/em> steht hierbei f\u00fcr <em>subject under test<\/em>. So kann ich bei vielen Variablen innerhalb des Tests leicht erkennen, was eigentlich zu testen ist. Dies ist die Vorbereitung, eine Instanz der zu testenden Klasse erstellen.<\/p>\n<p>Anschlie\u00dfend wird die zu testende Methode aufgerufen und abschlie\u00dfend das Ergebnis gepr\u00fcft.<\/p>\n<p>Die Ergebnispr\u00fcfung geschieht in Unit Test mit <em>assertions, <\/em>also mit <em>Behauptungen<\/em>. Hier behaupten wir, dass die Fibonacci Zahl am Index 0 = 1 ist, ebenso wie die Zahl am Index 1. Die Assert-Klasse von MS UnitTesting stellt einge Behauptungen bereit, z.B. um Boolsche-Ausdr\u00fccke oder auf Null zu pr\u00fcfen.<\/p>\n<p>Lasse ich nun \u00fcber das Men\u00fc von Visual Studio &#8222;<em>Test \/ Run \/ All Tests<\/em>&#8220; alle Test laufen, so wird mir das Ergebnis des Tests im Test Explorer angezeigt.<\/p>\n<p><a href=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/FirstUnitTestResultInTestExplorer.png\"><img decoding=\"async\" loading=\"lazy\" class=\" size-full wp-image-76 aligncenter\" src=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/FirstUnitTestResultInTestExplorer.png\" alt=\"FirstUnitTestResultInTestExplorer\" width=\"272\" height=\"227\" \/><\/a><\/p>\n<p>Ab jetzt kann ich nach jeder kleinen \u00c4nderung mit de<em>r <\/em>Tastenkombination<em> Strg+R, A<\/em> alle Tests laufen lassen und erhalte somit ein Feedback, ob meine \u00c4nderung die Funktion der bereits gepr\u00fcften Methoden ver\u00e4ndert hat. Gr\u00fcn hei\u00dft, alles ok. Bei einem fehlerhaften Test wird dies in rot angezeigt, so dass ich zun\u00e4chst den Fehler korrigieren kann, bevor ich weitermache.<\/p>\n<p>Erweitern wir die Testmethoden um die Pr\u00fcfung auf die ersten vier Fibonacci Zahlen.<\/p>\n<pre class=\"lang:default decode:true\" title=\"Unit Test GetFirst4Numbers\">        [TestMethod]\r\n        public void First4NumbersAreCorrect()\r\n        {\r\n            Fibonacci sut = new Fibonacci();\r\n            var numbers = sut.GetFirstNNumbers(4);\r\n            Assert.AreEqual(1, numbers[0]);\r\n            Assert.AreEqual(1, numbers[1]);\r\n            Assert.AreEqual(2, numbers[2]);\r\n            Assert.AreEqual(3, numbers[3]);\r\n        }<\/pre>\n<p>Das Testergebnis zeigt und einen Fehler &#8211; wird ja Zeit, dass hier mal jemand testet!<\/p>\n<p><a href=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/FailingUnitTestResultInTestExplorer.png\"><img decoding=\"async\" loading=\"lazy\" class=\" size-medium wp-image-77 aligncenter\" src=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/FailingUnitTestResultInTestExplorer-213x300.png\" alt=\"FailingUnitTestResultInTestExplorer\" width=\"213\" height=\"300\" srcset=\"https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/FailingUnitTestResultInTestExplorer-213x300.png 213w, https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/FailingUnitTestResultInTestExplorer.png 273w\" sizes=\"(max-width: 213px) 100vw, 213px\" \/><\/a><\/p>\n<p>Als vierte Fibonacci Zahl erwarten wir die 3, tats\u00e4chlich gibt die Methode aber 2 zur\u00fcck. Nun l\u00e4sst sich gezielt dieser Test debuggen und siehe da &#8211; die Methode hat noch nie funktioniert, da sich bei der Berechnung ein Fehler eingeschlichen hat &#8211; oh man! Wir korrigieren die Zeile wie folgt und addieren den <strong>Vorg\u00e4nger<\/strong> mit dem <strong>Vorvorg\u00e4nger<\/strong>.<\/p>\n<pre class=\"lang:default decode:true\" title=\"New algorythm\">            for (int i = 2; i &lt; n; i++)\r\n            {\r\n                fibonacciNumbers.Add(fibonacciNumbers[i - 1] + fibonacciNumbers[i - 2]);\r\n            }<\/pre>\n<p>Ein erneuter Aufruf der Tests best\u00e4tigt &#8211; so ist&#8217;s besser.<\/p>\n<p><a href=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/TwoCorrectUnitTests.png\"><img decoding=\"async\" loading=\"lazy\" class=\" size-full wp-image-78 aligncenter\" src=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/TwoCorrectUnitTests.png\" alt=\"TwoCorrectUnitTests\" width=\"272\" height=\"164\" \/><\/a><\/p>\n<p>Nun k\u00f6nnte ich weitere Unit Tests erg\u00e4nzen und anschlie\u00dfend den Code der Fibonacci-Klasse umbauen oder erg\u00e4nzen und kann durch immer wieder ausgef\u00fchrte Tests pr\u00fcfen, ob noch alle Ergebnisse wie erwartet berechnet werden.<\/p>\n<p>An dieser Stelle verzichte ich allerdings darauf und zeige noch eine andere M\u00f6glichkeit mit Behauptungen &#8211; assertions &#8211; zu arbeiten. Dazu installiere ich per <a title=\"NuGet im Visual Studio\" href=\"http:\/\/invidit.de\/blog\/nuget-im-visual-studio\/\">NuGet die Bibliothek FluentAssertions<\/a> f\u00fcr mein Testprojekt.<\/p>\n<p><a href=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/NuGetInstallFluentAssertions.png\"><img decoding=\"async\" loading=\"lazy\" class=\" size-medium wp-image-79 aligncenter\" src=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/NuGetInstallFluentAssertions-300x112.png\" alt=\"NuGetInstallFluentAssertions\" width=\"300\" height=\"112\" srcset=\"https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/NuGetInstallFluentAssertions-300x112.png 300w, https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/03\/NuGetInstallFluentAssertions.png 652w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Diese Bibliothek ist als <em>fluent interface<\/em> aufgebaut, was bedeutet, dass die Methodenaufrufe sehr sprechend formuliert werden. Dabei wird immer von dem zu \u00fcberpr\u00fcfenden Objekt ausgegangen, welches ein bestimmtes Verhalten aufweisen <em>sollte<\/em>. Unser zweiter Unit Test k\u00f6nnte damit so aussehen:<\/p>\n<pre class=\"lang:default decode:true\" title=\"UnitTest with FluentAssertions\">        [TestMethod]\r\n        public void First4NumbersAreCorrect()\r\n        {\r\n            Fibonacci sut = new Fibonacci();\r\n            var numbers = sut.GetFirstNNumbers(4);\r\n            numbers.Should().BeEquivalentTo(new int[] { 1, 1 , 2, 3});\r\n        }<\/pre>\n<p>Dieses Beispiel hat leider nicht das Potential die M\u00f6glichkeiten und die Lesbarkeit von FluentAssertions in voller Breite zu demonstrieren. Dennoch kann die Behauptung nun als echter Satz gelesen und damit sehr leicht verstanden werden. In unserem Fall:<\/p>\n<blockquote><p>numbers.Should().BeEquivalentTo(new int[] { 1, 1 , 2, 3});<\/p><\/blockquote>\n<p>Also: <em>numbers<\/em> sollte equivalent sein zu einer Liste mit den Werten 1, 1, 2, 3.<\/p>\n<p>Die Grammatik funktioniert im englischen allerdings besser, weshalb der Code nochmal besser lesbar ist, als diese &#8222;\u00dcbersetzung&#8220;.<\/p>\n<p>Diese Art der Assertions sind selbst dann gut lesbar, wenn ich die Signatur der Assert-Methoden &#8211; also welche Parameter was bedeuten &#8211; nicht kenne.<\/p>\n<p><strong>Wichtig:<\/strong> das Testergebnis zeigt weiterhin an, dass alles wie erwartet funktioniert \ud83d\ude42<\/p>\n<p>&nbsp;<\/p>\n<h2>Zusammenfassung<\/h2>\n<p>In diesem Artikel haben wir uns grunds\u00e4tzliche Unit Tests angeschaut und haben hinterfragt, warum diese hilfreich sind. Wir haben das Testframework Microsoft UnitTesting genutzt sowie die Erweiterung f\u00fcr sprechende Behauptungen mit FluentAssertions.<\/p>\n<p>&nbsp;<\/p>\n<p>Viel Spa\u00df beim Ausprobieren und Happy Coding w\u00fcnschen<\/p>\n<p>eure Spa\u00df-Coder<\/p>\n<p>&nbsp;<\/p>\n<p><em>Verwendete Werkzeuge:<\/em><\/p>\n<ul>\n<li>Visual Studio 2013 Community (<a title=\"https:\/\/www.visualstudio.com\/en-us\/products\/visual-studio-community-vs.aspx\" href=\"https:\/\/www.visualstudio.com\/en-us\/products\/visual-studio-community-vs.aspx\" target=\"_blank\">https:\/\/www.visualstudio.com\/en-us\/products\/visual-studio-community-vs.aspx<\/a>)<\/li>\n<li>Microsoft UnitTesting (<a title=\"https:\/\/msdn.microsoft.com\/de-de\/library\/hh694602.aspx\" href=\"https:\/\/msdn.microsoft.com\/de-de\/library\/hh694602.aspx\" target=\"_blank\">https:\/\/msdn.microsoft.com\/de-de\/library\/hh694602.aspx<\/a>)<\/li>\n<li>Fluent Assertions (<a title=\"https:\/\/github.com\/dennisdoomen\/fluentassertions\" href=\"https:\/\/github.com\/dennisdoomen\/fluentassertions\" target=\"_blank\">https:\/\/github.com\/dennisdoomen\/fluentassertions<\/a>)<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hallo Spa\u00df-Coder. Unit Tests sind eine coole Sache. Warum? Weil ich vor meinen \u00c4nderungen am Code leicht pr\u00fcfen kann, ob alles wie beabsichtigt funktioniert. Dann mache ich meine \u00c4nderungen und kann anschlie\u00dfend wieder pr\u00fcfen, ob immer noch alles funktioniert. Damit sinkt f\u00fcr mich die Gefahr, bei Code\u00e4nderungen bestehende Funktion kaputt zu machen. Es muss nicht [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":78,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[90],"tags":[],"_links":{"self":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/47"}],"collection":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/comments?post=47"}],"version-history":[{"count":21,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/47\/revisions"}],"predecessor-version":[{"id":108,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/47\/revisions\/108"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media\/78"}],"wp:attachment":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media?parent=47"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/categories?post=47"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/tags?post=47"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}