I am trying to write a unit test for the following class:
@Transactional
public class EditorHelper {
private static SessionFactory sf;
static {
ClassPathResource hbr = new ClassPathResource("hibernate.cfg.xml");
File hbCfg = null;
try {
hbCfg = hbr.getFile();
} catch (IOException e) {
e.printStackTrace();
}
if (hbCfg != null) {
sf = new AnnotationConfiguration().configure(hbCfg).buildSessionFactory(); // <-- Stack trace points here
}
}
public static void setSf(SessionFactory sf) {
EditorHelper.sf = sf;
}
}
There are some other methods, but this setup code is what’s relevant to my question. In my unit test, I want to mock (using EasyMock) the SessionFactory object sf, as well as the Session and Transaction objects it will return:
public class EditorTest {
private SessionFactory sf;
private Session s;
private Transaction tx;
private Long id = 1L;
private String idStr = id.toString();
@Before
public void setUp() {
sf = EasyMock.createMock(SessionFactory.class);
s = EasyMock.createMock(Session.class);
tx = EasyMock.createMock(Transaction.class);
EditorHelper.setSf(sf); // <-- Stack trace points here
EasyMock.expect(sf.getCurrentSession()).andReturn(s);
EasyMock.expect(s.beginTransaction()).andReturn(tx);
}
// Tests go here
}
When I try to run this with JUnit, I get the following error:
java.lang.NoSuchFieldError: INSTANCE
at org.hibernate.type.BasicTypeRegistry.<init>(BasicTypeRegistry.java:94)
at org.hibernate.type.TypeResolver.<init>(TypeResolver.java:59)
at org.hibernate.cfg.Configuration.<init>(Configuration.java:250)
at org.hibernate.cfg.Configuration.<init>(Configuration.java:302)
at org.hibernate.cfg.AnnotationConfiguration.<init>(AnnotationConfiguration.java:87)
at com.mypkg.helper.EditorHelper.<clinit>(EditorHelper.java:38)
at com.mypkg.model.EditorTest.setUp(EditorTest.java:29)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
There is no public INSTANCE variable on sf that I can see. I’m new to EasyMock, so I think my question is: what should I tell my mock to return for INSTANCE, and how do I tell it to do that? I don’t know why the SessionFactory setup code is being called by setSf() at all, so that’s another mystery. The more general question is: how should I mock up a SessionFactory object anyway?
Update
I figured out that catching the exception without doing anything will work just fine. I have changed my EditorHelper class as follows:
@Transactional
public class EditorHelper {
private static SessionFactory sf;
static {
...
if (hbCfg != null) {
try { // New try block lets the initializaiton fail
sf = new AnnotationConfiguration().configure(hbCfg).buildSessionFactory();
} catch (NoSuchFieldError e) {
e.printStackTrace();
}
}
...
Once this static block completes, I can set the SessionFactory member to point to my mock object and everything works from there.
The code is being run because it is inside a static initialization block. Once your test refers to
EditorHelper,the JVM will load the class and this initialization block will run and attempt to create aSessionFactoryfrom theAnnotationConfigurationinstance which is configured with the config XML file.Which class are you trying to test? I note that the test is
EditorTestand the class isEditorHelper. Is this intentional, and are you actually trying to test anEditorclass?