I'm trying to do the same thing. I have a solution that works for me - yours may vary (and you might not love the solution... it's a bit low-level).
I came across an article on the net where they were using a custom class loader to do something similar which served as inspiration. If anyone can see how to improve then suggestions would be welcome btw. For deployment I rely on container injection of the EntityManager but for testing I create it myself using this code:
final Thread currentThread = Thread.currentThread();
final ClassLoader saveClassLoader = currentThread.getContextClassLoader();
currentThread.setContextClassLoader(new ClassLoaderProxy(saveClassLoader));
EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("test");
em = emFactory.createEntityManager();
Then the ClassLoaderProxy is about as minimal as you can get and just redirects requests for META-INF/persistence.xml to META-INF/test-persist.xml:
public class ClassLoaderProxy extends ClassLoader {
public ClassLoaderProxy(final ClassLoader parent) {
super();
}
@Override
public Enumeration<URL> getResources(final String name) throws IOException {
if (!"META-INF/persistence.xml".equals(name)) {
return super.getResources(name);
} else {
System.out.println("Redirecting persistence.xml to test-persist.xml");
return super.getResources("META-INF/test-persist.xml");
}
}
}
Just to explain this a bit more:
- There are two persistence.xml files (one named persistence.xml that is used outside testing and one named test-persist.xml that is used for tests).
- The custom class loader is only active for unit tests (for deployment everything is normal)
- The custom class loader redirects requests for "META-INF/persistence.xml" to the test version ("META-INF/test-persist.xml").
I was originally hitting some problems because Hibernate will revert back (somehow) to the classloader that was used to load Hibernate (at least I think that is what was going on). I've found that putting the ClassLoader switching code (the first block) as a static block in your Test case it will get loaded before Hibernate but that, depending on your unit test structure you may also need to put the same code in other places (yuck).