# JUnit unter Eclipse: Problem mit Exception



## Professor Chaos (28. Aug 2008)

Hallo,

führt man eine JUnit Testklasse mit mehreren Testmethoden unter Eclipse aus, so werden alle Methoden nacheinander ausgeführt. Je nach dem, ob sie erfolgreich oder nicht erfolgreich beendet werden, steht im JUnit Übersichtsfenster hinter der jeweiligen Testmethode ein gründer Haken oder ein rotes X. Aber selbst, wenn (unvorhergesehene) Exceptions geworfen werden, werden ALLE Methoden ausgeführt.

Also, ich habe zwei Testmethoden, die nacheinander auseführt werden. Eigentlich sollten beide Methoden ohne Fehler (insb. ohne Exceptions) ausgeführt werden. Es heißt, dass man Methoden, die potentiell Exceptions werfen können, dies im Testcase aber nicht vorgesehen ist, nicht mit einen try-catch statement umgeben soll.

Das habe ich getan.

So, nun komme ich endlich zu meinem Problem:
Eine unvorhergesehen Exception wird geworfen und die JVM stoppt! Ich bekomme auf der Konsole die Exception präsentiert, aber es wird nur meine erste JUnit Testmethode ausgeführt, nicht aber die zweite. Entsprechend sehe ich in der oben beschriebenen Übersicht weder einen grünen Haken (das ist klar), noch ein rotes X! Es existiert aber keine System.exit(0)-Anweisung. Es wird nur "normal" eine Exception geworfen. Aber diese killt JUnit. Was könnten hierfür mögliche Ursachen sein?

Hier ein Minimalbsp. meines TestCodes:


```
/**
 * @throws MyException1
 * @throws MyException2
 */
public void testOne() throws MyException1, MyException2{

	String[] callingArgument = new String[]{"1","2"};

	System.out.println();
	TestedClass.main(callingArgument);
	System.out.println();
}

/**
 * @throws MyException1
 * @throws MyException2
 */
public void testTwo() throws MyException1, MyException2{

	String[] callingArgument = new String[]{"3","4"};

	System.out.println();
	TestedClass.main(callingArgument);
	System.out.println();
}
```

Nochmals auf den Punkt gebracht: Wird TestedClass mit testOne aufgerufen, so wird Exception1 geworfen (aber auf der Konsole, statt im dafür vorgesehenen JUnit Fenster) und testTwo wird nicht mehr ausgeführt! Ich erwarte aber, dass testOne als nicht erfolgreich gekennzeichnet wird (rotes X), die Exception im dafür vorgesehenen JUnit Fenster aufgelistet wird und testTwo trotzdem ausgeführt wird.
In anderen Testcases war dies bislang auch immer der Fall, nur funktiniert es hier nciht mehr. Hat jemand eine Idee für eine mögliche Ursache?

Hier die Exception:

```
java.io.IOException: MY SELF WRITTEN MESSAGE
	at (EDIT: MY CLASSNAMES, ETC)
	at testsWithJUnit.Test.testOne(Test.java:54)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at junit.framework.TestCase.runTest(TestCase.java:168)
	at junit.framework.TestCase.runBare(TestCase.java:134)
	at junit.framework.TestResult$1.protect(TestResult.java:110)
	at junit.framework.TestResult.runProtected(TestResult.java:128)
	at junit.framework.TestResult.run(TestResult.java:113)
	at junit.framework.TestCase.run(TestCase.java:124)
	at junit.framework.TestSuite.runTest(TestSuite.java:232)
	at junit.framework.TestSuite.run(TestSuite.java:227)
	at org.junit.internal.runners.OldTestClassRunner.run(OldTestClassRunner.java:76)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
```


----------



## maki (28. Aug 2008)

Exception handling in Unittests ist imho grundlegend falsch (mit einer einzigen Ausnahme).
Was willst du denn mit deiner Exception machen??? Kannst doch gar nicht sinnvoll darauf reagieren...

Entweder ein Test läuft durch, oder er schlägt fehl (fail()), im Falle einer Exception gibt es einen Error.

So sollte dein Code eher aussehen:

```
public void testOne() throws Exception {

   String[] callingArgument = new String[]{"1","2"};
   TestedClass.main(callingArgument);
   assertXXX( "message", condition);
}

public void testTwo() throws Exception {

   String[] callingArgument = new String[]{"3","4"};
   TestedClass.main(callingArgument);
   assertXXX( "message", condition);
}
```


----------



## Professor Chaos (28. Aug 2008)

maki hat gesagt.:
			
		

> Was willst du denn mit deiner Exception machen??? Kannst doch gar nicht sinnvoll darauf reagieren...


Ich möchte ja gar nicht darauf reagieren, der Punkt ist doch, dass diese Exception in meinem TestCase eigentlich gar nicht geworfen werden dürfte. Da sie aber dennoch geworfen wird, soll mir JUnit natürlich mitteilen: "testOne() failed, da die folgende Exception geworfen wurde".

Aber das passiert nunmal nicht! Statt dass die geworfene Exception im dafür vorgesehenen JUnit-Fenster dargestellt wird, wird sie auf die Konsole ausgegeben. Außerdem wird danach der zweite Test nicht durchgeführt. Beides sind Verhaltensweisen, die so nicht gedacht sind.



			
				maki hat gesagt.:
			
		

> So sollte dein Code eher aussehen:


Das ändert aber nichts. Aber gut, dann ändere ich es eben mal ab:


```
public void testOne() throws Exception {

   String[] callingArgument = new String[]{"1","2"};
   TestedClass.main(callingArgument);
   assertTrue("blub!",42>23);
}

public void testTwo() throws Exception {

   String[] callingArgument = new String[]{"3","4"};
   TestedClass.main(callingArgument);
   assertTrue("blub!",42>23);
}
```
Und was ist nun? Natürlich noch immer dasselbe Problem: Das assertTrue wird gar nicht erst erreicht, da TestedClass eine Exception wirft. Das ist ja eigentlich auch nichts schlechtes. Das Problem ist nur, dass nach dieser Exception testTwo() nicht ausgeführt wird, und dass die Exception eben nicht (sorry, ich wiederhole mich) im dafür vorgesehenen JUnit Fenster angezeigt wird, sondern auf der Konsole.


----------



## maki (28. Aug 2008)

> "testOne() failed, da die folgende Exception geworfen wurde".


Wie gesagt, sollte eigentlich einen Error anstatt ein Failed produzieren, aber abbrechen dürfte der Test deswegen eigentlich nicht.

Hab es gerade hiermit bei mir gestest (JUnit 3.8), beide Tests werden ausgeführt, bei testError wird ein Error angezeigt:

```
public class ErrorTestCase extends TestCase {
	
	public void testError() 
	throws Exception {
		throw new Exception("Testing error");
	}
	
	public void testAfterError()
	throws Exception {
		assertTrue(true);
	}
}
```


----------



## Professor Chaos (28. Aug 2008)

maki hat gesagt.:
			
		

> > "testOne() failed, da die folgende Exception geworfen wurde".
> 
> 
> Wie gesagt, sollte eigentlich einen Error anstatt ein Failed produzieren, aber abbrechen dürfte der Test deswegen eigentlich nicht.


Achso, ja, ich meinte eigentlich auch einen Error, habe mich nur falsch ausgedrückt.



			
				maki hat gesagt.:
			
		

> Hab es gerade hiermit bei mir gestest (JUnit 3.8), beide Tests werden ausgeführt, bei testError wird ein Error angezeigt:


Wenn ich deine TestCases vor meine schiebe, werden sie auch korrekt ausgeführt, d.h. er zeigt mir bei testError() korrekt das rote X an (mit der Exception-Meldung im JUnit), und bei testAfterError() korrekt den grünen Haken, genau so, wie ich es gerne hätte. Führt er danach allerdings meine Methode testOne() aus, ist es wieder dasselbe Spiel: Es erscheint weder ein grüner Haken, noch ein rotes X. Und außerdem wird die Exception wieder auf der Konsole ausgegeben, statt im JUnit Fenster. Mir ist das ein Rätsel...

Es wird noch seltsamer. Die Exception, die geworfen wird, ist (korrekter Weise, ich kenne den Fehler) eine IOException, siehe: 

```
java.io.IOException: MY MESSAGE	at [...]
```
Das seltsame ist nun, dass ich diese Exception nicht abfangen kann! Hier der modifizierte Code:


```
public void testOne() throws IOException{
		String[] callingArgument = new String[]{"1","2"};

		try{
			TestedClass.main(callingArgument);
		}catch(IOException e){
			System.out.println("strange...");
			System.out.println(e.getMessage());
		}
		
		assertTrue("blub!",42>23);
		System.out.println();
	}
```
Auch wenn ich eine Exception abfange (das sollte schließlich in jedem Fall funktionieren), ändert sich nichts.

Also, noch irgendwelche Ideen, wieso JUnit nicht in der Lage ist, diese Exception abzufangen?

Ich wollte noch posten, welche JUnit Version ich nutze, finde das aber nicht heraus... Wo kann man das nachlesen? Jedenfalls ist es wohl eine Version 4.x, welche, weiß ich aber nicht.


----------



## maki (28. Aug 2008)

Die gestestete Klasse macht aber keinen System.exit(0) o.ä?

Könnte ja sein dass die Klasse die Exception auf Sysout ausgibt und dann die VM beendet, etwas anderes fällt mir auf die schnelle nciht ein.


----------



## Professor Chaos (28. Aug 2008)

maki hat gesagt.:
			
		

> Die getestete Klasse macht aber keinen System.exit(0) o.ä?
> 
> Könnte ja sein dass die Klasse die Exception auf System.out ausgibt und dann die VM beendet, etwas anderes fällt mir auf die Schnelle nicht ein.


Diese Idee hatte ich natürlich auch, aber leider ist dem nicht so. Btw. war das daher auch eine meiner ersten Aussagen:  



			
				Professor Chaos hat gesagt.:
			
		

> Es existiert aber keine System.exit(0)-Anweisung. Es wird nur "normal" eine Exception geworfen.


Ich bin daher überfragt. Wer Rat weiß, bitte posten, egal wie alt dieser Thread hier bis dahin sein wird. Falls ich nämlich selbst des Rätsels Lösung finde, werde ich dies hier posten.


----------



## Professor Chaos (29. Aug 2008)

Schweren Herzens und mit gesenktem Kopf  kann ich nun die Lösung präsentieren:

Es gab leider tatsächlich eine System.exit(0)-Anweisung. Ich GARANTIERE, dass ich danach (per Befehl) gesucht habe, denn das war ja auch meine erste Idee als mögliche Ursache. Ich weiß nicht, wieso ich es damals nicht fand, womöglich ein TypeO.

Die Klasse TestedClass.main() hat regulär eine IOException geworfen, und in ihr befand sich die exit()-Anweisung auch nicht. Aber in ihr wurde eine weitere Klasse aufgerufen, in welcher die IO-werfende Zeile von einem Try-Catch-Block umgeben war. Sobald dieser Block die IO aufgefangen hat, wurde sie auf der Konsole ausgegeben und die JVM beendet.

Sorry, Maki, für das unnötige Beanspruchen deiner Zeit und danke für die Hilfe.


----------



## maki (29. Aug 2008)

Ente gut, alles gut


----------

