LazyInitializationException mentre l'unità di prova di classi entità Hibernate per l'uso in primavera, utilizzando TestNG
-
20-09-2019 - |
Domanda
Nella mia configurazione Primavera, ho chiesto che la sessione dovrebbe rimanere aperta in mio punto di vista:
<bean name="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory" ref="sessionFactory"/>
<property name="flushMode" value="0" />
</bean>
Tuttavia, questo fagiolo obiously non considera mio test di unità TestNG come una visione. ;-) Va tutto bene, ma c'è un fagiolo simile per i test di unità in modo che evito il LazyInitializationException temuto mentre unit test? Finora, la metà dei miei test di unità muoiono a causa di esso.
Il mio test di unità si presenta tipicamente come questo:
@ContextConfiguration({"/applicationContext.xml", "/applicationContext-test.xml"})
public class EntityUnitTest extends AbstractTransactionalTestNGSpringContextTests {
@BeforeClass
protected void setUp() throws Exception {
mockEntity = myEntityService.read(1);
}
/* tests */
@Test
public void LazyOneToManySet() {
Set<SomeEntity> entities = mockEntity.getSomeEntitySet();
Assert.assertTrue(entities.size() > 0); // This generates a LazyInitializationException
}
}
Ho provato a cambiare il setup () a questo:
private SessionFactory sessionFactory = null;
@BeforeClass
protected void setUp() throws Exception {
sessionFactory = (SessionFactory) this.applicationContext.getBean("sessionFactory");
Session s = sessionFactory.openSession();
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(s));
mockEntity = myEntityService.read(1);
}
ma credo che questo è il modo sbagliato per andare a questo proposito, e mi rovinare la transazione per le prove successive. C'è qualcosa come un OpenSessionInTestInterceptor, ci sono modi migliori di fare questo, o è questo il modo di farlo e in quel caso che cosa ho capito male su di esso?
Saluti
Nik
Soluzione
Umm .. non essere una smart-ass qui, ma non è quello che è stato destinato per setUp()
.
L'idea di base è quella di avere i test essere autosufficienti e rientrante nel senso che non dovrebbe dipendere dal database di avere record particolari, né si dovrebbe modificare in modo permanente il database nel tuo test. Il processo, quindi, è quello di:
- Crea tutti i record necessari
setUp()
- Esegui i test reali
- Clean up (se necessario) in
tearDown()
(1), ciascuna (2), e (3) tutti corrono in transazioni separate - da qui il problema che stai ricevendo con LazyInitializationException. Spostare mockEntity = myEntityService.read(1);
dal setUp nella vostra prova effettiva (s) e andrà via; utilizzare Impostazione se avete bisogno di creare alcuni dati di test, non come supplemento diretto al tuo singolo test.
Altri suggerimenti
I utilizza JUnit per i miei test, quindi è necessario per adattare il seguente esempio per TestNG. Personnaly Io uso SpringJUnit4ClassRunner di legare le transazioni in una classe di test di base:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/applicationContext-struts.xml")
@TransactionConfiguration(transactionManager = "transactionManager")
@Transactional
public abstract class BaseTests {
E in "@Before", ho iniettare un MockHttpServletRequest nella RequestContextHolder:
@Before
public void prepareTestInstance() throws Exception {
applicationContext.getBeanFactory().registerScope("session", new SessionScope());
applicationContext.getBeanFactory().registerScope("request", new RequestScope());
MockHttpServletRequest request = new MockHttpServletRequest();
ServletRequestAttributes attributes = new ServletRequestAttributes(request);
RequestContextHolder.setRequestAttributes(attributes);
.......