Issue
In an Jave EE application, I want to create a base test for in-memory database integration test, to initialize the EntityManagerFactory
and EntityManager
. Also, the service bean to test is not determined, so I make it generic.
I have:
class="lang-java prettyprint-override">package xxxxx;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import static org.mockito.Mockito.mockingDetails;
import static org.mockito.Mockito.spy;
/**
* T: the service bean class to test
*/
public abstract class H2DBIntTestBase<T> {
protected EntityManager realEntityManager;
protected static EntityManagerFactory factory;
protected T serviceBean;
public abstract void setServiceBean();
public abstract String getPUName();
@Before
public void setup() {
// as we cannot statically get class name in @BeforeClass of super class, we have to do
// it like this. We don't care repetitive creation, as they are the same one, so we don't
// guard it with sychronization/double check.
if (factory == null) {
factory = Persistence.createEntityManagerFactory(getPUName());
}
realEntityManager = factory.createEntityManager();
EntityManager spy = spy(realEntityManager);
setServiceBean();
try {
// inject the real entity manager, instead of using mocks
Field entityManagerField = serviceBean.getClass().getDeclaredField("entityManager");
entityManagerField.setAccessible(true);
entityManagerField.set(serviceBean, spy);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new AssertionError("should not reach here");
}
}
@After
public void teardown() {
realEntityManager.close();
}
}
And, in my concrete int test:
@RunWith(MockitoJUnitRunner.class)
public class MyServiceBeanIntTest extends H2DBIntTestBase<MyServiceBean> {
private Query<String> inputQuery;
@Override
public void setServiceBean() {
super.serviceBean = new SubscriptionHistoryPersistenceServiceBean();
}
@Override
public String getPUName() {
return serviceBean.getClass().getName();
}
@Before
public void setup() {
inputQuery = new Query<>();
... // other stubbings
}
@Test
public void test1() {
try {
// when
List<SubscriptionHistory> actual = serviceBean.doSth(inputQuery, Enum.TypeA);
// <----------- here serviceBean is always null, why?
// then
// assertions
} catch (DataLookupException e) {
throw new AssertionError("should not reach here");
}
}
}
But, I always have NPE in the test, at first in @After
, then in my @Test
.
Why my serviceBean
is not initialized? Shouldn't @BeforeClass
and @Before
of super tests are running BEFORE child classes?
Mockito: org.mockito:mockito-core:1.10.19
JUnit: junit:junit:4.11
I am not using Spring/Spring Boot.
Solution
Why my serviceBean is not initialized?
Because you've overridden setup()
in the subclass.
Either give the subclass (or superclass) setup()
a different name, or invoke the superclass one from the subclass.
Answered By - Andy Turner
Answer Checked By - Mildred Charles (JavaFixing Admin)