LazyInitializationException при модульном тестировании классов сущностей Hibernate для использования в Spring с использованием TestNG - PullRequest
1 голос
/ 09 октября 2009

В моей конфигурации Spring я просил оставить сеанс открытым в моих представлениях:

  <bean name="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
    <property name="sessionFactory" ref="sessionFactory"/>
    <property name="flushMode" value="0" />
  </bean> 

Однако этот компонент явно не рассматривает мои модульные тесты TestNG как представление. ;-) Все в порядке, но есть ли похожий компонент для модульных тестов, чтобы избежать страшного исключения LazyInitializationException во время модульного тестирования? Пока из-за этого умирает половина моих юнит-тестов.

Мой юнит-тест обычно выглядит так:

@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
  }



}

Я пытался изменить setUp () на это:

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);
}

но я считаю, что это неправильный путь, и я испортил транзакцию для последующих тестов. Есть ли что-то вроде OpenSessionInTestInterceptor, есть ли лучшие способы сделать это, или это способ сделать это, и в таком случае, что я неправильно понял?

Приветствия

Nik

Ответы [ 2 ]

6 голосов
/ 09 октября 2009

Я использую JUnit для своих тестов, поэтому вам нужно адаптировать следующий пример к TestNG. Персонально Я использую SpringJUnit4ClassRunner для привязки транзакций в базовом тестовом классе:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/applicationContext-struts.xml")
@TransactionConfiguration(transactionManager = "transactionManager")
@Transactional
public abstract class BaseTests {

И в «@Before» я вставляю запрос MockHttpServletRequest в 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);

     .......

Я взял информацию из руководства

1 голос
/ 09 октября 2009

Ммм ... не для того, чтобы быть умником, но это не то, для чего setUp() предназначался.

Основная идея состоит в том, чтобы ваши тесты были самодостаточными и повторяющимися, то есть вы не должны зависеть от базы данных, имеющей определенные записи, и не должны постоянно изменять базу данных в своем тесте. Процесс, таким образом, заключается в следующем:

  1. Создать все необходимые записи в setUp()
  2. Запустите ваши фактические тесты
  3. Очистить (при необходимости) в tearDown()

(1), каждый (2) и (3) все выполняются в отдельных транзакциях - отсюда проблема, которую вы получаете с LazyInitializationException. Переместите mockEntity = myEntityService.read(1); из набора в ваши фактические тесты, и они исчезнут; используйте setUp, если вам нужно создать некоторые тестовые данные, а не как прямое дополнение к вашему индивидуальному тесту.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...