Нужно объяснить необходимость предварительной очистки, чтобы избежать ложных срабатываний при тестировании с Spring? - PullRequest
9 голосов
/ 25 августа 2010

В документации на пружину , касающейся тестирования , говорится:

Избегайте ложных срабатываний при тестировании кода ORM

Когда вы тестируете код с использованием инфраструктуры ORM, такой каккак JPA или Hibernate, очистите базовый сеанс в тестовых методах, которые обновляют состояние сеанса.Если не очистить базовый сеанс платформы ORM, это может привести к ложным срабатываниям: ваш тест может пройти, но тот же код вызывает исключение в реальной производственной среде.В следующем примере тестового примера на основе Hibernate один метод демонстрирует ложное срабатывание, а другой метод правильно отображает результаты сброса сеанса.

Может кто-нибудь объяснить, почему мне нужно вызвать flush?

Ответы [ 4 ]

3 голосов
/ 25 августа 2010

Ну, вы на самом деле пропустили интересную часть, пример :) Вот оно:

// ...

@Autowired
private SessionFactory sessionFactory;

@Test // no expected exception!
public void falsePositive() {
    updateEntityInHibernateSession();
    // False positive: an exception will be thrown once the session is
    // finally flushed (i.e., in production code)
}

@Test(expected = GenericJDBCException.class)
public void updateWithSessionFlush() {
    updateEntityInHibernateSession();
    // Manual flush is required to avoid false positive in test
    sessionFactory.getCurrentSession().flush();
}

// ...

То, что этот пример пытается проиллюстрировать, заключается в том, что если вы на самом деле не flush сеанс (AKA кэш первого уровня) для синхронизации изменений в памяти с базой данных, вы на самом деле не тестируете интеграцию базы данных и не можете тестировать реальное ожидаемое поведение или пропущенная проблема.

Например, база данных может вернуть ошибку, скажем, из-за нарушения ограничения, и если вы не попадете в базу данных, вы не будете демонстрировать это правильное поведение, как в falsePositive() тестовом методе выше. Этот метод тестирования должен завершиться с ошибкой или ожидать исключения, но он просто пройдет. С другой стороны, другой метод тестирования со сбросом проверяет реальное поведение. Отсюда и необходимость flush.

1 голос
/ 15 мая 2014

Тестирование с пометкой Spring с @Transactional удобно, но не так, как будет выполняться ваш производственный код.Аннотация @Transactional запустит транзакцию до запуска тестового метода и откатит ее после завершения метода теста.

Пока фиксации предшествует сброс, откат не выполняется, поэтому ручнойflush - это механизм безопасности, обеспечивающий преобразование всех изменений сущностей в операторы SQL.

Более подходящим вариантом было бы явное отображение границ транзакции следующим образом:

@Test
public void testRootObjects() {

    final Company newCompany = new Company();
    newCompany.setName("TV Company");

    final Long companyId = transactionTemplate.execute(new TransactionCallback<Long>() {
        @Override
        public Long doInTransaction(TransactionStatus transactionStatus) {
            entityManager.persist(newCompany);
            return newCompany.getId();
        }
    });
    Company detachedCompany = transactionTemplate.execute(new TransactionCallback<Company>() {
        @Override
        public Company doInTransaction(TransactionStatus transactionStatus) {
            Company attachedCompany = entityManager.find(Company.class, companyId);
            assertEquals(newCompany, attachedCompany);
            assertEquals(newCompany.hashCode(), attachedCompany.hashCode());
            return attachedCompany;
        }
    });
    assertEquals(newCompany, detachedCompany);
    assertEquals(newCompany.hashCode(), detachedCompany.hashCode());
}

* TransactionTemplate зафиксирует ваш код, поэтому нет необходимости в ручных сбросах.

Если вы вызываете методы сервиса @Transactional через их интерфейс, вам вообще не понадобится транзакция транзакции, так как вы вызываете прокси Spring, который будет вызывать TransactionInterceptor (при условии, что вы указали Spring, чтобы он знал о аннотациях транзакций:) и поэтому транзакции будут начаты / совершены от вашего имени.

1 голос
/ 25 августа 2010

В документации Spring используется неверная концепция. Было ясно

но тот же код создает исключение в рабочей, производственной среде

А вот и Википедия

Ошибка типа II, также известная как «ошибка второго рода», ошибка β, или «ложноотрицательный результат» : ошибка отказа от отклонения нулевой гипотезы, когда она на самом деле не правда. Примером этого может быть, если тест показывает, что женщина не беременна, тогда как в действительности она есть.

Если вы видите пример, предоставленный Spring, производственная среда выдает исключение (A GenericJDBCException), , но оно не было обнаружено . Чтобы увидеть , вы должны вызвать базовый коммит при использовании какого-либо поставщика ORM.

Определение тестовых шаблонов XUnit

Ситуация, при которой тест проходит , хотя тестируемая система не работает должным образом .

То есть правильная концепция является ложной Отрицательной

@Test // no expected exception!
public void falseNegative() {
0 голосов
/ 04 января 2018

Кто-нибудь проверял аннотацию @TransactionConfiguration?Если вы используете аннотацию @Transactional, управляемую вашим проектом, вы можете просто установить @ TransactionConfiguration (defaultRollback = false ,actionManager = "YourTransactionManager") в вашем тестовом примере будет работать отлично, надеюсь, это поможет вам.

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