# Fragen zu JUnit und Assertions



## hasenbrot (25. Nov 2011)

Hallo,
ich habe bereits einiges über JUnit gelesen, was mir aber in einem konkreten Fall nicht unbedingt weiterhilft, wenn es darum geht, herauszufinden, welche Codebereiche überhaupt getestet werden müssen bzw. wo sich eine Assertion lohnt und wo nicht. Manche Bereiche, wie z.B. Netzwerk- und Dateioperationen, verlangen eindeutig nach einem Test. Nach welchen kritischen Stellen sollte man sonst noch Ausschau halten?


----------



## Andgalf (25. Nov 2011)

Nun es gibt durchaus die Meinung, das nicht eine einzige Zeile code ungetestet sein sollte, ob das realistisch ist, steht auf einem anderen Blatt Papier.

Auf jeden Fall ist das ein recht großer Themenbereich.

Stichwörter um Fragestellungen ums testen zu vertiefen sind:

Test Driven Development (TDD)
Unit Test v.s. Integrations / Akzeptanztests


Lektüre:
Clean Code von Uncle Bob Martin
Agile Testing 
...


----------



## hasenbrot (25. Nov 2011)

Es stellt sich z.B die Frage, ob es Sinn macht, Methodenargumente zu testen. Sinnvoll sind doch aber Tests in allen Bereichen, in denen Invarianten auftreten, z.B. Schleifen, switch- und if-Anweisungen, oder?


----------



## kama (25. Nov 2011)

Hallo,

pragmatisch gehe ich in der Art vor, dass zuerst Tests schreibe wo ich der Meinung bin, dass die nötig sind...bzw. schreibe die Tests vorher...

Dann erstelle ich eine Code-Coverage und schaue mir die Bereich genau an, wo eben keine Code-Abdeckung vorliegt und entscheide anhand dessen wo ich noch Tests schreiben sollte bzw. muss...

Gruß
Karl Heinz Marbaise


----------



## hasenbrot (25. Nov 2011)

Meine Frage bezieht sich ja darauf, wo Tests überhaupt nötig sind, also wie man routiniert die "heißen" Stellen im Code findet, die nach einem Test verlangen.


----------



## Andgalf (25. Nov 2011)

hasenbrot hat gesagt.:


> also wie man routiniert die "heißen" Stellen im Code findet, die nach einem Test verlangen.



Wie schon gesagt im Prinzip verlangt jede Stelle im Code einen Test. Es heißt also eher die Stellen zu finden, die ungetestet bleiben können ... Getter und Setter z.B. im Zweifelsfall lieber einen Test zuviel als einen zu wenig.


----------



## hasenbrot (25. Nov 2011)

Aber eine hohe Testabdeckung garantiert ja noch nicht, dass der Code richtig ist, oder? Es kann ja durchaus sein, dass der Programmierer viele wenig kritische Bereiche getestet hat, während der eine oder andere kritische Bereich ungetestet geblieben ist.

Abgesehen von den Unit Tests gibt es ja noch die einfachen Java Assertions, die man direkt in den Code schreibt, deshalb frage ich mich, welche Assertions ich in eine Test-Methode einer Testklasse schreibe und welche ich direkt im Code belassen kann.


----------



## AlexSpritze (25. Nov 2011)

Bzgl. Getter/Setter-Methoden ist das interessant: JUnit FAQ. Wenn ein Setter wirklich nur eine Zeile Code mit einer Zuweisung ist, dann lohnt sich dafür wohl eher kein Test. Aber im Gegenteil könnte er schaden, wenn du tausend Setter-Methoden testest, das kostet Zeit etc.


----------



## Andgalf (25. Nov 2011)

hasenbrot hat gesagt.:


> Aber eine hohe Testabdeckung garantiert ja noch nicht, dass der Code richtig ist, oder? Es kann ja durchaus sein, dass der Programmierer viele wenig kritische Bereiche getestet hat, während der eine oder andere kritische Bereich ungetestet geblieben ist.



Stimmt, aber die Wahrscheinlichkeit, dass kritische Stellen ungetestet sind ist erheblich geringer als bei einer niedrigen Testabdeckung.

Außerdem ist es auch ziemlich entscheident, dass man den Richtigen(sinnvollen) Test schreibt und nicht nur irgendeinen. (sind alle Schwellenwerte / Extremwerte getested, Corner-Cases beachtet ...)



hasenbrot hat gesagt.:


> Abgesehen von den Unit Tests gibt es ja noch die einfachen Java Assertions, die man direkt in den Code schreibt, deshalb frage ich mich, welche Assertions ich in eine Test-Methode einer Testklasse schreibe und welche ich direkt im Code belassen kann.



Die Assertions, die man direkt in den Code schreibt haben aus meiner Sicht gar nichts mit Unit-Testing zu tun. Diese werden ja nur überprüft, wenn man das Programm mit dem entsprechenden Parameter started. Ich vermeide es solche Assertions zu verwenden und teste lieber entsprechend mit Unit-Test.

BTW: Ich stehe auch auf dem Standpunkt, kein Projekt ohne Continuous-Integration-Server


----------



## kama (25. Nov 2011)

Hallo,



hasenbrot hat gesagt.:


> Aber eine hohe Testabdeckung garantiert ja noch nicht, dass der Code richtig ist, oder? Es kann ja durchaus sein, dass der Programmierer viele wenig kritische Bereiche getestet hat, während der eine oder andere kritische Bereich ungetestet geblieben ist.


Genau dafür gibt es ja Code-Coverage...Mann muss sich eine Code Coverage schon mit Verstand und Zeit anschauen...nur so nach dem Motto: 70 % ...alles Ok...reicht nicht....
Was kritisch ist muss man eben rauskriegen...durch anschauen sprich Code lesen und verstehen und dann eben eine Entscheidung treffen...für oder gegen einen Test(s).

Tests garantieren grundsätzlich nicht die Richtigkeit von Code...auch nicht das keine Fehler vorhanden sind...



hasenbrot hat gesagt.:


> Abgesehen von den Unit Tests gibt es ja noch die einfachen Java Assertions, die man direkt in den Code schreibt, deshalb frage ich mich, welche Assertions ich in eine Test-Methode einer Testklasse schreibe und welche ich direkt im Code belassen kann.


Die ich nie nutze, da ich dann immer die JVM anders starten muss und dass bekomme ich in keiner Umgebung bzw. seitens des Betriebes durch...


Gruß
Karl Heinz Marbaise


----------



## hasenbrot (25. Nov 2011)

Wie kann ich nun aber Invarianten, Vor- und Nachbedingungen einzelner Methoden in einen Unit Test verlagern, anstatt einfach asserts in den Code zu schreiben?

Bsp.:


```
public int methode(int a) {       
        assert a % 2 == 0;   // Vorbedingung
    .........
    assert ergebnis > 5;   // Nachbedingung
   return ergebnis;
    }
```


----------



## JohannisderKaeufer (25. Nov 2011)

AlexSpritze hat gesagt.:


> Bzgl. Getter/Setter-Methoden ist das interessant: JUnit FAQ. Wenn ein Setter wirklich nur eine Zeile Code mit einer Zuweisung ist, dann lohnt sich dafür wohl eher kein Test. Aber im Gegenteil könnte er schaden, wenn du tausend Setter-Methoden testest, das kostet Zeit etc.




```
public void setName(String n){
  this.name = name;
}
```

Wie erkennst du sowas?

Der Test (als Unittest) muss ja auch nicht ständig ausgeführt werden, wenn gerade an einer anderen Baustelle gearbeitet wird.


----------



## kama (26. Nov 2011)

Hi,


JohannisderKaeufer hat gesagt.:


> ```
> public void setName(String n){
> this.name = name;
> }
> ...


Dabei geht mir meine IDE auf die Nerven...WARNING: "The assigment to variable name has no effect" ..?

Zeugt aber auch davon, dass man diesen setter nicht generiert hat...(IDE...)

Gruß
Karl Heinz Marbaise


----------



## AlexSpritze (26. Nov 2011)

JohannisderKaeufer hat gesagt.:


> ```
> public void setName(String n){
> this.name = name;
> }
> ...



Ja, genau, das ist wirklich fies. Und da hilft dann die IDE, muss sie helfen.  ... wie kama schon gesagt hat.


----------



## hasenbrot (27. Nov 2011)

Soweit ich weiß sind Unit Tests nur dazu geeignet, das äußere Verhalten einer Klasse zu testen, nicht aber die Innereien eines Algorithmus. Ist das richtig?


----------



## kama (27. Nov 2011)

Hi,

hm...was verstehst Du denn unter den "Innerreien" eines Algorithmus ? 
Man möchte doch wissen, ob die Klasse das macht was sie machen soll....sprich, dass bzw. die ergebnisses liefert, die ich erwarte...

Ein Algorithmus liefert doch auch ein Ergebnis und somit kann ich das Ergebnis prüfen, sprich einen Test dazu schreiben...

Gruß
Karl Heinz Marbaise


----------



## hasenbrot (27. Nov 2011)

Ich meine z.B. die im Beispiel 25.11.2011 19:07 genannten Vor- und Nachbedingungen. Soweit ich weiß, lässt sich das nicht mit einem Unit Test testen, weil der Test nicht in die Klasse "hineinschauen" kann.


----------



## kama (27. Nov 2011)

Hallo,

bei den geannten Bedingungen würde ich auch in der entsprechenden Methoden Exception erzeugen (eben genau aus diesem Grunde Nutze ich in einem solchen Falle eben Exception und nicht assertion, abgesehen davon, dass ich dazu immer die JVM anders starten muss) und die kann man durchaus mit einem Unit Test Prüfen und somit sehen, ob sich das so verhält wie man möchte...

Für mich würde die Methode ungefähr so ausehen (ungetestet)

```
public int methode(int a) {       
    if (a % 2 != 0) {
      throw new IllegalArgumentException("Bedingung a % 2 == 0 nicht erfüllt");
    }
   ....
    if (ergebnis > 5) {
      throw new IllegalCalculationException("Ergebnis > 5!");
   }

   return ergebnis;
    }
```

Ein weiterer Nachteil, meine Meinung nach, von assertion ist, dass diese erst zur Laufzeit geprüft werden. Dann ist es aber schon zu spät...bedeutet im praktischen, dass dann eine Software schon im Test ist (oder gar noch schlimmer schon in Produktion)...

Oben genante Bedinungen gehören nun mal mit Exceptions gesichert, damit ich eben merke, dass etwas falsch läuft....und dazu gehört eben ein entsprechender Unit Test..

Gruß
Karl Heinz Marbaise


----------



## hasenbrot (27. Nov 2011)

Danke für die Antwort. Assertions prüfen Bedingungen zur Laufzeit, während Exceptions schon zur Compilezeit auftreten, was ja ein Vorteil ist. Der einzige Vorteil der Assertions wäre dann nur, dass sie vom Compiler komplett ignoriert werden können, während if-Abfragen, die Exceptions auslösen,  ständig ausgeführt werden. Sehe ich das so richtig?


----------



## _ebm_ (7. Dez 2011)

Wie schon weiter oben geschrieben, garantieren Tests nicht die Richtigkeit sondern sollen auf längere Sicht garantieren, dass sich das Verhalten eines Codebereiches nicht ungemerkt ändert. Die Richtigkeit muss oft eher die Laufzeit beweisen. Ich bin auch kein Freund von 100% Coverage. Bei großen Projekten ist das schlicht unbezahlbar und viele Kunden wollen das auch nicht bezahlen. Für mich sind Codestellen, die a) Magie enthalten (zB Reflection) oder b) unverständlich sein können, mit Unittests abzusichern. Wobei b) bitte auch zu refaktorieren ist


----------



## fastjack (7. Dez 2011)

Aus meiner Erfahrung ist das Prüfen von Methodenargument durchaus sinnvoll. Ich habe z.B. zu oft NullPointerException irgendwo tief unten gehabt, weil Schichten höher gar nix geprüft wurde. Da kann eine IllegalArgumentException schon Gold wert sein 

Ansonsten teste ich, bis die Coverage 100%ig ist. Wenn Du TDD anfängst ist das kein Problem, da Du keinen Ballast mehr produzierst (Methoden die sowieso niemals benutzt werden usw.).


----------



## _ebm_ (7. Dez 2011)

Für NULL-Prüfung von Argumenten gibt es inzwischen sogar eine JSR-303-Implementierung vom Hibernate-Team (Hibernate-Validator [*] ). Das hat jetzt nichts mit DB/ORM zutun. Da kann man dann folgendes machen:


```
public Long add(@NotNull Long a, @NotNull Long b) {

  return a + b;

}
```

Maven:
[XML]<dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-validator</artifactId>
	<version>4.2.0.Final</version>
</dependency>[/XML]

[*] Hibernate Validator - Bean Validation reference implementation - JBoss Community


----------

