Java – How to unit test custom ClassLoader

javaunit testing

For some reasons, I need a child-first ClassLoader. Such ClassLoader doesn't exist in the JDK, so I'm writing it. Since this is a key component of my use case, I'd like it to be heavily tested. To ensure it's not changed without breaking the behavior, I want to be extremely thorough and test all that's testable automatically.

So how can I test it? How should I make my basic unit test? I'm kind of stuck as to where to start (especially since there's at least one super call in each method) and I'm looking for some guidelines to start.

My main idea is the following. Is there anything wrong with it?

/src/main/resources/parent.jar
                    child.jar

The file parent.jar contains a class com.example.Example which is a basic Supplier returning "parent". The file child.jar contains a class com.example.Example which is a basic Supplier returning "child".

I'd be creating a standard URLClassLoader for parent.jar, and I'd use my custom ClassLoader to load child.jar. Then I'd load the class com.example.Example and check that it's actually returning "child" instead of "parent".

More complex test cases are thought about, but I just need a confirmation to start: is this enough for the basic test? Is this really what I should be testing in my unit tests? If not, what is?


I'm quite sure the code is not needed for this, but in case you're curious or whatever, here's it.

import java.io.*;
import java.net.*;
import java.util.*;

class ChildFirstClassLoader extends URLClassLoader {

  ChildFirstClassLoader(ClassLoader parent) {
    super(new URL[0], parent);
  }

  @Override
  // Make this method available in this package.
  protected void addURL(URL url) {
    super.addURL(url);
  }

  @Override
  protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    synchronized (getClassLoadingLock(name)) {
      Class<?> c = findLoadedClass(name);
      if (c == null) {
        try {
          c = findClass(name);
        } catch (ClassNotFoundException ignore) {
          c = super.loadClass(name, resolve);
        }
      }
      if (resolve) {
        resolveClass(c);
      }
      return c;
    }
  }

  @Override
  public URL getResource(String name) {
    URL url = findResource(name);
    if (url == null) {
      url = super.getResource(name);
    }
    return url;
  }

  @Override
  public Enumeration<URL> getResources(String name) throws IOException {
    List<URL> urls = new ArrayList<>();
    urls.addAll(Collections.list(findResources(name)));
    urls.addAll(Collections.list(super.getResources(name)));
    return Collections.enumeration(urls);
  }
}

Best Answer

So how can I test it? How should I make my basic unit test? I'm kind of stuck as to where to start (especially since there's at least one super call in each method) and I'm looking for some guidelines to start.

Granted I don't know much about ClassLoaders or Java for that matter, but I would have trouble unit testing this. One of the reasons being, as you state, your class inheriting from URLClassLoader. Even if we could mock out the superclass somehow, I would not have a lot of trust in the tests verifying that my implementation does what is intended to do.

So for what it's worth, I would lean on writing a more integrated test here: Maybe having a few "fixture" folders containing examples like the one you presented:

  • Fixtures
    • CanSuccessfullyLoad
      • parent.jar
      • child.jar
    • ThrowsAnErrorOnLoad
      • justparent.jar

That would result in me writing a test for each of those cases and "using" the parent/child classes in a very simple manner just to verify it loaded or failed to load as I expected.