Как протестировать сценарий отката весной

Мне нужно протестировать сценарий отката для этой службы:

@Service
public class MyService2 {

    private final Entity2Repo entity2Repo;

    public MyService2(Entity2Repo entity2Repo) {
        this.entity2Repo = entity2Repo;
    }

    public void create(Long entity1Id) {
        Entity2 entity2 = new Entity2();
        entity2.assignToEntity1(entity1Id);
        entity2Repo.save(entity2);
    }
}

Я создал этот тестовый пример интеграции:

@Transactional
@RunWith(SpringRunner.class)
@SpringBootTest(classes = JpaApplication.class)
public class MyServiceIntTest {

    @Autowired
    private Entity1Repo entity1Repo;

    @Autowired
    private EntityManager entityManager;

    @Test
    public void create() throws Exception {

        MyService2 mock = mock(MyService2.class);
        doThrow(new RuntimeException("bla bla")).when(mock).create(anyLong());


        MyService myService = new MyService(entity1Repo, mock);

        try {
            myService.create("some name");
            fail("should never fails");
        } catch (RuntimeException e) {
            assertThat(e.getMessage()).isEqualTo("bla bla");        // success
        }

        Entity1 dbEntity1 = (Entity1) entityManager.createQuery("from Entity1 where name = 'some name'").getSingleResult();

        assertThat(dbEntity1).isNull();                             // fail, however it should be null as it is rolled-back
    }
}

Возникает вопрос, почему объект организации все еще сохраняется в базе данных после отката?

РЕДАКТИРОВАТЬ: Полный исходный код на github: https://github.com/mhewedy-playground/test-transaction-rollback

Можете ли вы быстро попытаться расширить свой тест AbstractTransactionalJUnit4SpringContextTests? Также есть ли у вас bean-компонент PlatformTransactionManager в ApplicationContext, который загружается с помощью семантики @ContextConfiguration, как описано в документации?

hovanessyan 04.04.2018 09:46

@hovanessyan то же самое, я считаю, что Spring boot добавляет PlatformTransactionManager на основе типа источника данных (который был бы в моем случае JpaTransactionManager) (я просто печатаю в начале метода тестирования: org.springframework.orm.jpa.JpaTransactionManager@6e03db1f )

Muhammad Hewedy 04.04.2018 09:51

В приведенном выше коде есть проблема, экземпляр MyService, созданный в тесте, не управляется Spring, поэтому при вызове метода create транзакция не создается.

Muhammad Hewedy 04.04.2018 11:33
1
3
1 618
1

Ответы 1

Проблема заключалась в том, что я создавал объект MyService вне контекста Spring, а затем ожидал запуска диспетчера транзакций.

Я изменил тестовый код на следующий, и теперь он успешно работает:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = JpaApplication.class)
public class MyServiceIntTest {
    @Autowired
    private EntityManager entityManager;

    @Autowired
    private MyService myService;

    @MockBean
    private MyService2 myService2;

    @Transactional
    @Test(expected = RuntimeException.class)
    public void createWillRollback() throws Exception {

        doThrow(new RuntimeException("bla bla")).when(myService2).create(anyLong());

        myService.create("some name");

        assertThat(count()).isEqualTo(0);
    }

    @Transactional
    @Test
    public void create() throws Exception {

        doNothing().when(myService2).create(anyLong());

        myService.create("some name");

        assertThat(count()).isEqualTo(1);
    }

    private long count() {
        return ((Long) entityManager.createQuery("select count(*) from Entity1").getSingleResult());
    }
}

Эта строка: assertThat(count()).isEqualTo(0); никогда не достигается !!

Muhammad Hewedy 05.04.2018 09:23

Другие вопросы по теме