Подтвердить что ты не робот

Как откатить транзакцию базы данных при тестировании служб с помощью Spring в JUnit?

У меня нет проблем с тестированием моих DAO и служб, но когда я тестирую INSERT или UPDATE, я хочу отменить транзакцию и не повлиять на мою базу данных.

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

Это мой тест:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/META-INF/spring.cfg.xml")
@TransactionConfiguration(defaultRollback=true)
public class MyServiceTest extends AbstractJUnit38SpringContextTests  {
    @Autowired
    private MyService myService;

    @BeforeClass
    public static void setUpClass() throws Exception {
    }

    @AfterClass
    public static void tearDownClass() throws Exception {
    }

    @Test
    public void testInsert(){
        long id = myService.addPerson( "JUNIT" );
        assertNotNull( id );
        if( id < 1 ){
            fail();
        }
    }
}

Проблема в том, что этот тест завершится неудачно, потому что транзакция была отменена, но вставка в порядке! Если я удалю @TransactionConfiguration(defaultRollback=true), тогда тестовый проход, но новая запись будет вставлена ​​в базу данных.

@Test
@Transactional
@Rollback(true)
public void testInsert(){
    long id = myService.addPerson( "JUNIT" );
assertNotNull(id);
if( id < 1 ){
        fail();
    }
}

Теперь можно выполнить пробный проход правильно, но откат игнорируется, и запись вставляется в базу данных. Я отметил, что метод addPerson() внутри myService с @Transactional, очевидно. Почему игнорирование отката?

4b9b3361

Ответ 1

Вам необходимо расширить границы транзакций до границ вашего тестового метода. Вы можете сделать это, аннотируя свой тестовый метод (или весь тестовый класс) как @Transactional:

@Test 
@Transactional
public void testInsert(){ 
    long id=myService.addPerson("JUNIT"); 
    assertNotNull(id); 
    if(id<1){ 
        fail(); 
    } 
} 

Вы также можете использовать этот подход для обеспечения правильной записи данных перед откатом:

@Autowired SessionFactory sf;

@Test 
@Transactional
public void testInsert(){ 
    myService.addPerson("JUNIT"); 
    sf.getCurrentSession().flush();
    sf.getCurrentSession().doWork( ... check database state ... ); 
} 

Ответ 2

проверить

http://static.springsource.org/spring/docs/2.5.x/reference/testing.html

Раздел 8.3.4, в частности

Spring имеет несколько классов для тестирования, которые будут обертывать каждый тест в транзакции, поэтому БД не изменяется. Вы также можете изменить эту функциональность, если хотите.

Изменить - в зависимости от вашей информации, вы можете посмотреть

AbstractTransactionalJUnit38SpringContextTests в

http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/test/context/junit38/AbstractTransactionalJUnit38SpringContextTests.html

Ответ 3

Используйте следующую аннотацию перед классом:

@TransactionConfiguration(transactionManager = "txManager",defaultRollback = true)
@Transactional

здесь txManager - это диспетчер транзакций приложения.

Здесь txManager - это экземпляр или bean id менеджера транзакций из application context.

<!-- Transaction Manager -->
    <bean id="txManager"
          class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:annotation-driven transaction-manager="txManager" />

Добавьте свой код внутри метода setUp(), это будет выполняться в начале теста, а последний завершающий код должен быть помещен в метод teatDown(), который будет выполнен последним. или вы можете использовать вместо него @Before и @After аннотацию.

Ответ 4

Если ваш

myService.addPerson("JUNIT"); 

метод аннотируется как @Transactional, вы будете получать какой-то другой вид или ошибки, пытающиеся исправить это. Так что вам лучше просто проверить методы DAO.