How can I test a .class file was created?
Asked Answered
S

2

2

I want to unit test my code which will have to create a .java file compile it and then the corresponding .class file should be created.

How can I create the test to see if the ".class" file is created? I have added test already for its existence, now I'm trying to test the file is a valid class file.

I tried

 try  {
      Class.forName("Hello");
      throw AssertError();
 } catch( ClassNotFoundException e ) {
 }

 program.createClass();
 Class.forName("Hello");

But I don't really know how to dynamically add the path where the file is created to the classpath.

EDIT

URL Class loaded does the work.

This is how my test looks like now.

@Test
void testHello() throws MalformedURLException, ClassNotFoundException {
    URL[] url = {
            new URL("file:/home/oreyes/testwork/")
    };

    try {
        new URLClassLoader(url).loadClass("Hello");
        throw new AssertionError("Should've thrown ClassNotFoundException");
    } catch ( ClassNotFoundException cnfe ){

    }
    c.process();
    new URLClassLoader(url).loadClass("Hello");
}
Somebody answered 15/11, 2009 at 20:28 Comment(1)
hehe testng is not a typo, but the name of the testing framework :)Somebody
A
4

Use a new instance of an URLClassLoader, pointing to the root folder where you created the target class file. Then, use the Class.forName(String,ClassLoader); method with the dynamically created URLClassLoader to load the new class.

To show that it works, the following test case will create a source file, write some Java code in there and compile it using the Java 6 ToolProvider interfaces. Then, it will dynamically load the class using an URLClassLoader and invoke a reflective call to its class name to verify it's really this class which has been generated on the fly.

@Test
public void testUrlClassLoader() throws Exception {
    Random random = new Random();
    String newClassName = "Foo" + random.nextInt(1000);
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
    List<File> files = new ArrayList<File>();
    File sourceFolder = new File(".");
    File sourceFile = new File(sourceFolder, newClassName + ".java");
    FileWriter fileWriter = new FileWriter(sourceFile);
    fileWriter.write("public class " + newClassName + " { { System.out.println(\""
            + newClassName + " loaded\"); }}");
    fileWriter.close();
    files.add(sourceFile);
    Iterable<? extends JavaFileObject> compilationUnits1 = fileManager
            .getJavaFileObjectsFromFiles(files);
    compiler.getTask(null, fileManager, null, null, null, compilationUnits1).call();
    fileManager.close();

    URL url = sourceFolder.toURI().toURL();
    URLClassLoader urlClassLoader = new URLClassLoader(new URL[] { url });
    Object newInstance = urlClassLoader.loadClass(newClassName).newInstance();
    assertEquals(newClassName, newInstance.getClass().getName());
}
Apery answered 15/11, 2009 at 20:31 Comment(2)
I've tried ` new URLClassLoader(new URL[]{new URL("file:~/testwork")});` but is not working.Somebody
~ is not a valid short cut for the home directory in Java. It only works in some Unix programs.Codfish
S
1

Instead of loading the class in order to verify it, you could shell out to a command like "file Hello.class" to see if it reports that it's a java class file, or even spawn a sub-process of java to load the class outside of your test JVM.

Salot answered 15/11, 2009 at 21:13 Comment(2)
such as... "javac Hello.java ; java Hello"? MMhhh could work. It is just that eventually this thing will create more and more stuff and I just wanted ( at this stage ) to test if the .class was created and if it was a valid java class ( my Hello.java is : class Hello{} )Somebody
Well, I didn't necessarily mean "javac Hello.java ; java Hello." You could just check with "file Hello.class" to see if the file is non-zero and has the right magic number to be a java class. Then if you want something stronger, you could have a new simple class that loads a your class by name with Class.forName("args[0]"). My point is that rather than restricting yourself to using the existing JVM, you can spawn a new process and work there.Salot

© 2022 - 2024 — McMap. All rights reserved.