views:

37

answers:

1

The question: Is there a way I can use a ClassLoader to test both the presence and absence of the library I'm checking for?

I have a some code which will use a particular library if available, or fall back to some embedded code if not. It works fine but I'm not sure how to unit test both cases in the same run, or if it's even possible. At the moment, my unit tests only check one case because the library is either in the main classpath or it's not.

The code I use to check for the library availability is basically:

boolean available;
try {
  Class.forName("net.sf.ehcache.CacheManager");
  available = true;
} catch (ClassNotFoundException e) {
  available = false;
}

I could potentially alter the way this is done, if it would make unit testing easier.

+1  A: 

You are trying to do two things at once:

  • test the different implementations of your code, and
  • test that the correct implementation is selected based on the circumstances (or, more generally, that your app works regardless of whether or not the library in question is present).

Separating the two tasks into distinct tests simplifies the problem. Thus, I would implement the two versions of your code as two Strategies, and put the code which checks the classpath and creates the necessary strategy into a Factory (Method). Then both strategies can be unit tested independent of classloader and classpath settings:

interface MyStrategy {
  public void doStuff();
}

class MyLibraryUsingStrategy implements MyStrategy {
  public void doStuff() {
    // call the library
  }
}

class MyEmbeddedStrategy implements MyStrategy {
  public void doStuff() {
    // embedded code
  }
}

In unit tests, you can simply create and test either of the concrete strategies:

@Test
void testEmbeddedStrategy() {
  MyStrategy strategy = new MyEmbeddedStrategy();
  strategy.doStuff();
  // assert results
}

A simple factory method to create the appropriate strategy:

MyStrategy createMyStrategy() {
  MyStrategy strategy;
  try {
    Class.forName("net.sf.ehcache.CacheManager");
    strategy = new MyLibraryUsingStrategy();
  } catch (ClassNotFoundException e) {
    strategy = new MyEmbeddedStrategy();
  }
  return strategy;
}

Since the factory code is fairly trivial, you may even decide not to write automated tests for it. But at any rate, testing the factory is more (part) of an integration test than a unit test; you can simply put together different setups of your app - one with and the other without the library in question - and see that both work properly.

Péter Török
In my case, the choice only determines which implementation of an interface to create, so the Strategy pattern isn't really needed on top of this. But both of the implementations are fully unit tested and you are right that the remaining code is trivial enough that it may not warrant a cumbersome setup of running tests with different classpaths.
Nick
@Nick, if I understand you correctly, you have already implemented Strategy :-)
Péter Török
Possibly - I'd just call it regular polymorphism! :)
Nick
Marking this as the answer as it's probably the closest I'm going to get.
Nick