Как я могу проверить нарушение ограничения при выполнении удаления в интеграционном тесте Spring? - PullRequest
2 голосов
/ 13 января 2020

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

например

INSERT INTO parent_rec (id) VALUES ("foo");
INSERT INTO child_rec (id, parent_id) VALUES ("bar", "foo");
COMMIT;
DELETE FROM parent_rec WHERE id = "foo"; -- bang!
@PersistenceContext
EntityManager em;

@Transactional
void testDelete() {
  // Set up records
  ParentRecord record = new ParentRecord("foo");
  em.persist(record);
  em.persist(new ChildRecord("bar", record));

  //delete
  mockMvc.perform(delete("/parent/foo")).andExpect(/* some error code */);
}

Однако у меня возникают проблемы. Если я добавлю аннотацию @Transactional на уровне метода или класса, записи не будут сохраняться до тех пор, пока не будет предпринята попытка удаления, поэтому удаление возвращает 200 OK, а не 400 Bad Request или подобное.

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

Можно ли выполнить sh то, что я хочу, без использования дополнительного уровня набор инструментов? Раньше я использовал DBUnit, чтобы делать что-то подобное, но если бы я мог избежать добавления дополнительных зависимостей, я бы предпочел сохранить их простыми.

Ответы [ 3 ]

1 голос
/ 21 января 2020

Запуск только некоторого кода в отдельной транзакции также пригодится. Вы можете достичь этого, например, создав метод для блока кода, который будет вызываться в транзакции:

protected <T> T getInsideTransaction(Function<EntityManager, T> transactional) {
    EntityManager em = null;
    EntityTransaction trx = null;
    try {
        em = entityManagerFactory.createEntityManager();
        trx = em.getTransaction();
        trx.begin();
        return transactional.apply(em);
    } catch (Throwable throwable) {
        throw throwable;
    } finally {
        if (trx != null) {
            if (!trx.getRollbackOnly()) {
                trx.commit();
            } else {
                trx.rollback();
            }
        }
        if (em != null) {
            em.close();
        }
    }
}

Теперь вы можете вызвать его так:

void testDelete() {
  // Set up records
  getInsideTransaction(em -> {
    ParentRecord record = new ParentRecord("foo");
    em.persist(record);
    em.persist(new ChildRecord("bar", record));
  }

  //delete
  mockMvc.perform(delete("/parent/foo")).andExpect(/* some error code */);
}

Вы можете вызвать произвольный блок кода в отдельной транзакции таким образом.

0 голосов
/ 25 января 2020

Весной специально для тестирования таких случаев в слое репозитория я использую, похоже, должно работать и у вас - org.springframework.test.context.transaction.TestTransaction. Обратите внимание на @Commit аннотацию о методе тестирования, иначе ваша запись не будет сохранена.

@Commit
void testDelete() {
  // Set up records
  ParentRecord record = new ParentRecord("foo");
  em.persist(record);
  em.persist(new ChildRecord("bar", record));
  TestTransaction.end()

  TestTransaction.start()
  //delete
  mockMvc.perform(delete("/parent/foo")).andExpect(/* some error code */);
}

Но, конечно, после фиксации вы должны удалить запись вручную.

0 голосов
/ 13 января 2020

В JEE я решил эти проблемы, просто разбив свой код на две части:

@Transactional(propagation = Propagation.REQUIRES_NEW)
public class ParentRecordTestFacade {

    public void create() {
        // Create record here
    }

    public void delete() {
        // Delete record here
    }
}

и затем вызывая оба метода в реальном модульном тесте один за другим.

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