Добавление @Transactional нарушает UnitTests, мешая JPA извлекать внешние ключи - PullRequest
1 голос
/ 03 апреля 2019

Я пытаюсь повысить скорость наших тестов базы данных flyway. Первоначальный метод должен был запускать flyway.clear() и flyway.migrate() между каждым тестовым прогоном. Проблема, однако, в том, что теперь у нас есть несколько потенциально долго выполняемых сценариев миграции с миграционного пути, и мы не хотим повторять их между каждым тестом.

Я пытался использовать пружинную аннотацию @Transactional для отката базы данных после каждого теста, тогда нам нужно запустить пролет только один раз.

Проблема в том, что как только я добавляю транзакции вокруг теста, JPA перестает извлекать внешние ключи. Я предполагаю, что это потому, что вложенные транзакции ведут себя не так, как я ожидаю, но я не смог выяснить, что я настроил неправильно.

Я разместил пример проекта здесь: ExampleSpringJpaHibernatePostgresqltest с проблемой (см. ExampleTest.java), но в итоге:

У меня есть сущности с внешним ключом следующим образом (я удалил ненужные, чтобы было легче читать):

@Entity
@Table(name = "parent")
public class ParentEntity {
    @Id
    @Column
    private Integer id;

    @Column
    private String name;

    @OneToMany(fetch = FetchType.EAGER)
    @JoinColumn(name = "fk_parent", referencedColumnName = "id")
    private Set<ChildEntity> children;
}
@Entity
@Table(name = "child")
public class ChildEntity {
    @Id
    @Column
    private Integer id;

    @Column
    private String name;

    @Column(name = "fk_parent")
    private Integer fkParent;
}

У меня есть тест, который использует parentRepository.findAll(). Если я окружу этот тест с помощью @Transactional, то тест не пройден, потому что parentEntity.getChildren() равен нулю. Хотя без транзакции и запуска flyway clear / migrate между каждым тестом все работает как положено.

    @Test
    @Transactional
    public void testReadWithDependencies() {
        ParentEntity savedParent1 = parentRepo.save(new ParentEntity("parent1"));
        childRepo.save(new ChildEntity("child1", savedParent1.getId()));

        Set<ChildEntity> acutalChildren = parentRepo.findAll().get(0).getChildren();

        // XXX When the tests are run with @Transactional, this assertion fails.
        assertThat(acutalChildren).isNotNull();
    }

1 Ответ

2 голосов
/ 03 апреля 2019

parentRepo.findAll не обновляет данные из базы данных, и вы не добавляете дочерний элемент к дочерним элементам в родительском элементе.

Поэтому нет дочерних объектов, назначенных родительской сущности.

Итак, если вы обновите сущность (я ввел EntityManger), ваш тест пройдет успешно:

@Test
@Transactional
public void testReadWithDependencies() {
    assertThat(parentRepo.findAll()).isEmpty();
    assertThat(childRepo.findAll()).isEmpty();

    ParentEntity savedParent1 = parentRepo.save(new ParentEntity("parent1"));
    childRepo.save(new ChildEntity("child1", savedParent1.getId()));

    List<ParentEntity> allParents = parentRepo.findAll();
    assertThat(allParents).hasSize(1);

    // Refresh
    ParentEntity parentEntity = allParents.get(0);
    entityManager.refresh(parentEntity);

    Set<ChildEntity> acutalChildren = parentEntity.getChildren();

    // XXX When the tests are run with @Transactional, this assertion fails.
    assertThat(acutalChildren).isNotNull();

    assertThat(acutalChildren).hasSize(1);
    assertThat(acutalChildren.iterator().next().getName()).isEqualTo("child1");
}
...