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.