Hallo Ihr,
ich umreisse mal grob das Problem:
Stellt euch vor ihr habt Schüler die Java lernen und Aufgaben (Quellcodes) lösen, die sie dann hochladen. Die landen dann alle in einem Ordner, der wahrscheinlich nach der SchülerID benannt ist. Ich möchte nun wissen, ob deren Quellcodes in etwa das tun was sie sollen. Darum habe ich hier eine Testingklasse die sich alle eingelieferten Quellcodes vornimmt.
Problem: die Javaklassen liegen ja vorher noch nicht vor, wenn ich die Testingklasse schreibe - das heißt ich könnte jetzt in jede einzelne java Datei reingucken und den Namen der Klasse rausfischen. Dieser wird ja benötigt, wenn man für JUnit die zu testende Klasse initiiert. Das beste wird sein, wenn ich für jede Aufgabe eine Codehülle vorgebe. Die Methoden werden dann von den Schülern gefüllt. So habe ich die Kontrolle über deren Quellcode und kann diesen auch generalisiert testen. Aber das Problem ist wie gesagt, wie ich dem Testprogramm zur Laufzeit alle Klassen bekannt machen kann, die es zu testen hat. So lange ich auch überlege, ich komme nur auf zwei Ansätze.
ich habe ein anderes Programm, dass den Ordner parst und den notwendigen Quellcode dann in die jeweilige Klasse schreibt. Das ist aber keine schöne Lösung wie ich finde
ich arbeite mit EJB, wo die Klassen ja vorher auch nicht alle bekannt sind - aber davon möchte ich wirklich noch absehen. Ich möchte das nicht zu sehr aufblähen, sondern das lokal laufen lassen. Ohne Webserver.
Es wäre echt toll, wenn ihr mir eure Erfahrungen und Ideen posten könntet. Ich kann doch unmöglich der Erste sein, der auf so eine Idee kommt.
das sollte relativ einfach sein, du musst halt paar Vorgaben machen
Hauptklasse mit den bestimmten Methoden müssen fest definiert sein
Alle Klassen müssen an einem bestimmten Platz liegen
du musst dann halt beim Starten deines Test den Classpath auf den Ordner und da die Hauptklasse ja fest definiert ist kannst du einen fest gehackten Test durchlaufen lassen.
am einfachsten: die schueler sollen schon den Unit test schreiben. Das hilft ihnen auch gleich zum probieren ob das was sie geloest haben richtig ist (und ich hoffe mal sie schreiben so und so code um das auszuprobieren).
Dann kannst du JUnit ueber alle Testklassen laufen lassen.
Wenn du keine Ahnung hast was da wie wo drinsteht schauts nicht gut aus ohne sich nicht komplett den Hals zubrechen bei den Bemuehungen.
Eine feste Interface Vorgabe muss schonmal sein - aber auch dann ist das “ich hol mir mal alle Klassen in Ordner X, hoffe dass sie die Implementierungen sind die ich brauch und nicht Hilfsklassen und lade alle dynamisch und starte” nicht trivial - machbar, aber zu viel Aufwand imo
Du gibst doch die Aufgabe vor oder ? D.h. du hast es auch in der Hand a) die Funktionalitaet abzugrenzen und b) Schnittstellen zu definieren. Daher wuerde ich den Schuelern eine Testklasse mit der zu fordernden Funktionalitaet mitgeben, die mithochgeladen werden muss. Darauf kannst du dann JUnit laufen lassen
So, mittlerweile habe ich Reflections entdeckt. Damit kann man genau das machen, was ich brauche. Das Problem ist allerdings, dass ich scheinbar irgendetwas falsch mache. Das Programm wirft mir immer eine “ClassNotFound”-Exception vor die Füße. Ausprobiert habe ich dabei schon den Quellcode aus “Java ist auch eine Insel” sowie diesen hier:
package ReflTest;
class CA
{
public void Hello()
{
System.out.println("Hallo Knollo");
}
}
public class ReflTest {
/**
* @param args
*/
public static void main(String[] args) {
try {
Class c = Class.forName("CA");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Kann mir irgendwer verraten, warum er die Klassen nicht zur Laufzeit finden kann? Würde mich brennend interessieren.
Vielen Dank für eure Zeit.
Ok, ich habs zwar bereits vermutet, aber es ist erforderlich, dass man auch den Namen des packages mit angibt. Also in diesem Fall Class c = Class.forName("ReflTest.CA");
Das Tutorial mit dem ich arbeitete verzichtete sicherlich auf Pakete, weshalb man das dort weglassen konnte.
Es ist zum Ausrasten. Warum ist es so verdammt eklig mit mehreren Paketen zu arbeiten? Bzw. nicht das Arbeiten ist bescheuert, sondern das ausführen von Class-Dateien. Klar, jetzt könnte man sagen “Was für ein n00b”. Und was das angeht habe ich auch noch nicht viele Erfahrungen, aber es kann doch nicht wahr sein, dass man selbst mit Suchfunktion und Google nicht schlauer wird. Beim Ausführen des Programms wird mir eine NoClassDefFoundError-Excp geschmissen. Die wurde hier im Forum schon öfter geschmissen und überall heißt es einfach nur “einfach Classpath” anpassen. Aber das ist nicht so, wie ich mir das vorstelle.
man stelle sich vor ich befinde mich in Ordner src. Dort gibt es zwei Unterordner -> aufgaben und logik. Das es sich um zwei Pakete handelt, dürfte klar sein. In Logik befindet sich die Main.java wo dann schließlich via Reflection eine Klasse gesucht wird die in aufgaben liegt. Das er richtig kompiliert steht außer Frage, denn ich benutze nun Class c = Class.forName("aufgaben.test"). Doch wird das Programm gestartet, kann er den aufgaben Ordner nicht finden. Gut, gehst du halt mal auf Konsolenebene und probierst dort herum. Das habe ich getan, ich habe -cp beansprucht.
Einmal aus dem Sourceordner heraus:
[Python]java logik/Main[/Python]
–> NoClassDefFound von aufgaben/test --> wrong name oder sowas
dann mit modifiziertem ClassPath:
[Python]java -cp .:aufgaben/ logik/Main[/Python]
Aber auch hier das Gleiche… wie funktioniert denn das nun? Ich dachte wenn ich ihm den Pfad zu der Klasse mitgebe, findet er alle .class-Dateien die dort enthalten sind. Aber reflection scheint über andere Pfade darauf zugreifen zu wollen, anders verstehe ich nicht, wieso er die Klassen nicht finden kann…
naja du musst sie jetzt noch compilen, weil die Java Dateien kannst du per Reflection nicht auslesen/ausführen
und wenn du sie compiliert hast dann ist es der letzte Fall von mir
die Dateien sind kompiliert und ich habe verstanden was deine Ausführungen mir erklärten. Das ist in etwa auch das Verhalten was ich davon erwartet habe. Aber er findet die Klassen trotzdem nicht.
public class test
{
public static void main(String[] args)
{
System.out.println("Hallo Knolloe");
try {
Class c = Class.forName("testpack.aufgaben.Vectors");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}```
Fehlermeldung:
```pwd && java -cp .:testpack/aufgaben/ testpack/test
/home/asd/Code/java/Test/
Exception in thread "main" java.lang.NoClassDefFoundError: testpack/aufgaben/Vectors (wrong name: aufgaben/Vectors)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
at testpack.test.main(test.java:9)
public class Vectors
{
public void hello()
{
System.out.println("was geht ab Knollo");
}
}```
Fehler gefunden, danke Eagle.. natürlich muss ich hier noch das package anpassen.. da fehlt das testpack davor. Jetzt muss ich nur noch Netbeans beibringen das auch so zu machen >_>
argh!.. irgendwo habe ich aufgeschnappt, dass in der forName()-Methode die Paketnamen klein geschrieben werden müssen. Das ist aber nicht richtig. Wenn das Paket einen großen Anfangsbuchstaben hat, muss der auch groß in der Methode stehen T_T Man sollte eben doch nicht alles glauben oder wenn dann auch richtig lesen >_>
Es gehört aber zur guten Form Paketnamen klein zu schreiben.
hehe, dann warst du Schlawiner das. Meine Idee ist nun, das gesamte package aus dem Projekt zu lösen. Nun stellt sich aber das Problem, dass ich nicht weiß, wie ich der Applikation beibringen soll externe packages zu finden. Also ich verwende nun einen Ordner “Aufgaben” in dem dann die class-Dateien drin sind. Mein reflectionprogramm soll dann darauf zugreifen können, ohne das aufgaben-package im Projekt enthalten zu haben. Das Ziel wird sein, dass ich meinem Programm am Anfang sage, wo er die class-Dateien findet und diese dann via Reflection ansteuern kann. Geht das so ohne weiteres?
Achya, ich will davon absehen irgendwelche jars im Projekt einzubinden. Das Programm soll am Ende völlig autark funktionieren, ohne dem Wissen welche Aufgaben es gibt. Das soll man dann über die gui einstellen (es wird darauf hinauslaufen ne xml zu laden in der dann steht wo die Aufgaben sind und welche Methoden wie getestet werden)