# Plugin - JUnit - Tests aus einem anderen Projekt ausführen



## dragon_ (27. Aug 2011)

Guten Tag,
ich arbeite an einem Plugin für die Eclipseumgebung. Dabei möchte ich JUnit Tests aus einem Zielprojekt laufen und auslesen können. Hierbei habe ich mithilfe der org.eclipse.jdt.junit.JUnitCore.findTestTypes() Methode die erforderlichen Testdateien aus dem Zielprojekt auslesen können, sodass ich die Namen der java Dateien habe. Mittels eines URLCLassLoaders kann ich die class Dateien des Zielprojektes lesen und laden. Diese ClassDateien braucht man nämlich um den junit.runner laufen zu lassen. In der Methode .runClasses(Class<?> ...) kann eine Liste von Classdateien übergeben werden.

Hierbei entsteht nun das Problem. Ich kann die class-Dateien ohne Probleme laden. Jedoch wird die Test Annotation(@Test) während des Testdurchlaufes nicht erkannt. Dies äußert sich zum einen dabei, dass bei einem Durchlauf der Methoden dieser class-Datei, keine Testannotation gefunden wird, was wiederrum während des Testrunnerdurchlaufes einen Fehler ergibt. Hier wird angezeigt, dass es keine Testmethoden gibt:


```
FehlerMessage: No runnable methods
Fehlertrace: java.lang.Exception: No runnable methods
at org.junit.runners.BlockJUnit4ClassRunner.validateI nstanceMethods(BlockJUnit4ClassRunner.java:177)
at org.junit.runners.BlockJUnit4ClassRunner.collectIn itializationErrors(BlockJUnit4ClassRunner.java:122 )
at org.junit.runners.ParentRunner.validate(ParentRunn er.java:269)
at org.junit.runners.ParentRunner.<init>(ParentRunner .java:66)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(Bl ockJUnit4ClassRunner.java:58)
at org.junit.internal.builders.JUnit4Builder.runnerFo rClass(JUnit4Builder.java:13)
at org.junit.runners.model.RunnerBuilder.safeRunnerFo rClass(RunnerBuilder.java:57)
at org.junit.internal.builders.AllDefaultPossibilitie sBuilder.runnerForClass(AllDefaultPossibilitiesBui lder.java:29)
at org.junit.runner.Computer.getRunner(Computer.java: 38)
at org.junit.runner.Computer$1.runnerForClass(Compute r.java:29)
at org.junit.runners.model.RunnerBuilder.safeRunnerFo rClass(RunnerBuilder.java:57)
at org.junit.runners.model.RunnerBuilder.runners(Runn erBuilder.java:93)
at org.junit.runners.model.RunnerBuilder.runners(Runn erBuilder.java:84)
at org.junit.runners.Suite.<init>(Suite.java:79)
at org.junit.runner.Computer.getSuite(Computer.java:2 6)
at org.junit.runner.Request.classes(Request.java:69)
at org.junit.runner.JUnitCore.run(JUnitCore.java:127)
at org.junit.runner.JUnitCore.runClasses(JUnitCore.ja va:76)
at de.hsrm.ilias_plugin.handlers.TestingHandler.execu te(TestingHandler.java:162)
at org.eclipse.ui.internal.handlers.HandlerProxy.exec ute(HandlerProxy.java:293)
at org.eclipse.core.commands.Command.executeWithCheck s(Command.java:476)
at org.eclipse.core.commands.ParameterizedCommand.exe cuteWithChecks(ParameterizedCommand.java:508)
at org.eclipse.ui.internal.handlers.HandlerService.ex ecuteCommand(HandlerService.java:169)
at org.eclipse.ui.internal.handlers.SlaveHandlerServi ce.executeCommand(SlaveHandlerService.java:241)
at org.eclipse.ui.internal.handlers.SlaveHandlerServi ce.executeCommand(SlaveHandlerService.java:241)
at org.eclipse.ui.menus.CommandContributionItem.handl eWidgetSelection(CommandContributionItem.java:829)
at org.eclipse.ui.menus.CommandContributionItem.acces s$19(CommandContributionItem.java:815)
at org.eclipse.ui.menus.CommandContributionItem$5.han dleEvent(CommandContributionItem.java:805)
at org.eclipse.swt.widgets.EventTable.sendEvent(Event Table.java:84)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.ja va:1669)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.ja va:1693)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.ja va:1678)
at org.eclipse.swt.widgets.Widget.notifyListeners(Wid get.java:1421)
at org.eclipse.swt.widgets.Display.runDeferredEvents( Display.java:3738)
at org.eclipse.swt.widgets.Display.readAndDispatch(Di splay.java:3306)
at org.eclipse.ui.internal.Workbench.runEventLoop(Wor kbench.java:2696)
at org.eclipse.ui.internal.Workbench.runUI(Workbench. java:2660)
at org.eclipse.ui.internal.Workbench.access$4(Workben ch.java:2494)
at org.eclipse.ui.internal.Workbench$7.run(Workbench. java:674)
at org.eclipse.core.databinding.observable.Realm.runW ithDefault(Realm.java:332)
at org.eclipse.ui.internal.Workbench.createAndRunWork bench(Workbench.java:667)
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(Pl atformUI.java:149)
at org.eclipse.ui.internal.ide.application.IDEApplica tion.start(IDEApplication.java:123)
at org.eclipse.equinox.internal.app.EclipseAppHandle. run(EclipseAppHandle.java:196)
at org.eclipse.core.runtime.internal.adaptor.EclipseA ppLauncher.runApplication(EclipseAppLauncher.java: 110)
at org.eclipse.core.runtime.internal.adaptor.EclipseA ppLauncher.start(EclipseAppLauncher.java:79)
at org.eclipse.core.runtime.adaptor.EclipseStarter.ru n(EclipseStarter.java:344)
at org.eclipse.core.runtime.adaptor.EclipseStarter.ru n(EclipseStarter.java:179)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Nativ e Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Native MethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(De legatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.eclipse.equinox.launcher.Main.invokeFramework( Main.java:622)
at org.eclipse.equinox.launcher.Main.basicRun(Main.ja va:577)
at org.eclipse.equinox.launcher.Main.run(Main.java:14 10)
at org.eclipse.equinox.launcher.Main.main(Main.java:1 386)
```

Wenn ich das selbe Szenario in einem normalen JavaProjekt ausführe funktioniert dies und es wird eine Test Annotation gefunden.

Wo könnte hier der Fehler liegen bzw. wie kann ich dieses Problem beheben? Für jede kleine Idee wär ich dankbar.


----------



## Wildcard (27. Aug 2011)

Wäre es nicht sinnvoll sich erstmal anzuschauen wie der Eclipse JUnit Runner das macht?


----------



## dragon_ (27. Aug 2011)

Vielen Dank für das schnelle Antworten. 

Ich nehme an du meinst, dass ich mir die JUnit Plugin Implementation anschauen sollte. Das heisst via Plugin Spy die Klassen anschaun. Das habe ich versucht, indem ich mir die JUnit-ViewPage angeschaut habe. Jedoch kam ich da nicht viel weiter. 
Die Frage stellt sich eben was verhält sich anders in einem lokalen Projekt als in einem Plugin, das class Dateien lädt und somit die Annotation verliert. Wie gesagt der gleiche Code verhält sich unterschiedlich.

Ich kann ja nochmal den Code den ich benutze posten:

```
if (firstElement instanceof IJavaProject) {
     IJavaProject javaproject = (IJavaProject) firstElement;
	try {
		IType[] classesWithTests = org.eclipse.jdt.junit.JUnitCore.findTestTypes(javaproject, null);
                TestClassLoader loader=new TestClassLoader();
                Class theClass=loader.classLoading("/testJava/bin/", "SimpleTest");

                //test ob annotation vorhanden
                Method[] methods = theClass.getMethods();
	             for( Method m : methods ) {
			 if( m.isAnnotationPresent( Test.class ) ) {
			     Test a = m.getAnnotation( Test.class );
			     System.out.println( "Methode:                 " + m.getName() );
	             }
	        }

               Class<?>[] testClasses={theClass};
					
	       Result r = JUnitCore.runClasses(testClasses);

               if(r.getFailureCount()>0){
		   System.out.println("fehler:"+r.getFailureCount());
		   for(Failure f:r.getFailures()){
			System.out.println("FehlerMessage: "+f.getMessage()+"\n"+
						"Fehlertrace: "+f.getTrace()+"\n"+
						"Fehlerdescription: "+f.getDescription());	
		   }
		}else if(r.wasSuccessful()){
			System.out.println("test erfolgreich");
		}
         } catch (OperationCanceledException e) {
			e.printStackTrace();
	} catch (CoreException e) {
				e.printStackTrace();
	}
}
```


----------



## Wildcard (28. Aug 2011)

> Ich nehme an du meinst, dass ich mir die JUnit Plugin Implementation anschauen sollte.


Ich meine damit das ich fie robuste Implementierung von Eclipse versuchen würde wiederzuverwenden anstatt es nachbauen zu wollen.


----------



## dragon_ (28. Aug 2011)

Ja da bin ich mittlerweile auch angelangt. Ich dachte halt dass man ganz einfach den Runner anstößt und gut ist. Dann war es eine endlose Suche um herauszufinden wie ich an den Codeteil komme um z.B. die Implementierung des Run-Buttons des Plugins zu bekommen. Das habe ich immer gesucht... Damit ich Eclipse bzw das Plugin die Arbeit machen lassen kann bzw verstehe wo diese Funktion des JUnitCore aufgerufen wird. Ich habe aber jetzt herausgefunden dass man mittels Import die bestehenden Plugins in den Workspace als Projects laden kann und dass ggf. das was ich suche im org.eclipse.jdt.junit.XX Plugin/Package liegt. D.h. ich habe immer nur im Kern versucht rumzusuchen.

Ich werde mal weiter in dem neuen Package suchen, wo es die Schnittstelle zum Kern gibt. Vielleicht bin ich erfolgreich


----------



## dragon_ (28. Aug 2011)

Leider blieb die Suche erstmal erfolglos. Den genauen Punkt zwischen der UI und dem JUnitCore habe ich nicht entdeckt. Mittels des Spy kann man nicht die erforderlichen Handler oder Klassen anschauen, in denen die Implementierung der Aktion steht. Daher weiss ich nicht was genau passiert, wenn man den "Run As...->JUnit Test" Eintrag benutzt.

Edit: Mittels der Methode launch(ISelection,String) kann ich die Selection(IJavaProject) übergeben, wodurch der ganze Testdurchlauf gestartet wird, und danach die JUnitTestView aufgerufen wird. D.h man müsste nur noch einen Listener in diesen Ablauf einhängen, damit man an die Resultate kommt.


----------



## dragon_ (31. Aug 2011)

Wildcard hat gesagt.:


> Ich meine damit das ich fie robuste Implementierung von Eclipse versuchen würde wiederzuverwenden anstatt es nachbauen zu wollen.



Also wenn ich das richtig verstanden habe, meinst du, dass ich eclipse sage: Führe JUnit Tests mit diesem Projekt aus? Wenn dies der Fall ist habe ich dies mithilfe des org.eclipse.jdt.junit packages und der launch(ISelection)-Methode geschafft. Das Problem was nun besteht ist, dass dies einen Job erstellt, der irgendwann vom System dann abgearbeitet wird. Hierbei wird nirgendswo in den JUnitCore gegangen. D.h. ich habe keinen Debug oder Einstiegspunkt. Ich kann nur den Durchlauf der JobErstellung überwachen. 

Die Frage wäre nämlich dann, ob ich alles was danach kommt selbst bauen muss oder ob ich einen Listener an den JUnitCore-Runner anhängen kann. Oder wie könnte ich den Einstiegspunkt in den JUnitCore bekommen, der irgendwann passiert?


----------



## Wildcard (1. Sep 2011)

Ich weiß es nicht, da ich es nie versucht habe, aber ich weiß, das man es herausfinden kann, indem man sich den Code des JUnit Launchers und der JUnit View anschaut.


----------

