транзакции и тестирование
От: зиг Украина  
Дата: 26.01.15 12:18
Оценка:
Опишу свою проблему максимально понятно.
Итак, есть у меня кусок кода A для которого я хочу понаписать юнит тесты (или, интеграционные, не так важно).

class A {
..
@Transactional(propagation=REQUIRES_NEW)
public void oneOfTheMethods() {

...
}
..
}


Написала тест:

@Transactional
public void testAlotOfSutff(){
 doSomePreparation();
 insertSomeRequiredData();
 callProcessB();
 ..
 //at the end, finally we can test processA
 callProcessA();

}


Теперь в чем суть проблемы:
мой тест вставляет всякие данные в тестовую базу, вызывает разные подпроцессы, и предполагается что после выполнения тесты все роллбечится, то есть мы не замусориваем тестовую базу ничем плохим, тестируем обе части кода — как которая что-то вставляет, и ту которая работает с этими данными, в общем много плюсов.
Все работало прекрасно. пока мне не понадобилось потестировать в конце как работает метод A.oneOfTheMethods на этих данных — оказалось, что он нифига не работает.
Т.к. он суспендит юниттестовскую транзакцию и создает новую транзакцию (из-за REQUIRED_NEW propagation!)
и соответственно "не видит" данных которые юниттест вставил до этого. СУБД Оракл — поэтому выставить isolation=READ_UNCOMMITTED не удается.
Что делать?

менять propagation только из-за юниттеста я не могу — вопервых он не зря там стоит этот пропагейшн, во=вторых мы не должны менять код который тестируем только потому что не можем нормально написать тест.
Что делать-то?

я согласна даже на чтонибудь типа рефлексией изменять уровень пропагации этого метода ТОЛЬКО для тестирования. но чтоб в продакшне был код без изменений. такое возможно?
Re: транзакции и тестирование
От: dimgel Россия https://github.com/dimgel
Дата: 26.01.15 12:33
Оценка: +2
Здравствуйте, зиг, Вы писали:

зиг>во-вторых мы не должны менять код который тестируем только потому что не можем нормально написать тест.


Неверно. Частенько рефакторят только ради тестируемости (и в качестве побочного эффекта улучшают архитектуру).

зиг>Что делать-то?


Лично я перед каждым тестом базу пересоздаю (у меня под это дело отдельный экземпляр SQL-сервера крутится с базой в tmpfs — т.е. в RAM). Так что никаких роллбэков-хэков мне не надо, и с этим подходом я могу даже selenium-тесты гонять на задеплоенном приложении, в которое уж точно rollback не подсунешь.
Re: транзакции и тестирование
От: andyag  
Дата: 26.01.15 12:59
Оценка: 1 (1) +2
Здравствуйте, зиг, Вы писали:

зиг>Что делать-то?

зиг>я согласна даже на чтонибудь типа рефлексией изменять уровень пропагации этого метода ТОЛЬКО для тестирования. но чтоб в продакшне был код без изменений. такое возможно?

Как решение в лоб — грохать базу и пересоздавать заново. Челябинский такой rollback
Re[2]: транзакции и тестирование
От: зиг Украина  
Дата: 26.01.15 13:14
Оценка:
Здравствуйте, andyag, Вы писали:

A>Здравствуйте, зиг, Вы писали:


зиг>>Что делать-то?

зиг>>я согласна даже на чтонибудь типа рефлексией изменять уровень пропагации этого метода ТОЛЬКО для тестирования. но чтоб в продакшне был код без изменений. такое возможно?

A>Как решение в лоб — грохать базу и пересоздавать заново. Челябинский такой rollback

неохота, некрасиво, долго муторно
а что никак с этой транзакцией поисхитряться не получится?
Re[3]: транзакции и тестирование
От: Qulac Россия  
Дата: 26.01.15 13:26
Оценка:
Здравствуйте, зиг, Вы писали:

зиг>Здравствуйте, andyag, Вы писали:


A>>Здравствуйте, зиг, Вы писали:


зиг>>>Что делать-то?

зиг>>>я согласна даже на чтонибудь типа рефлексией изменять уровень пропагации этого метода ТОЛЬКО для тестирования. но чтоб в продакшне был код без изменений. такое возможно?

A>>Как решение в лоб — грохать базу и пересоздавать заново. Челябинский такой rollback

зиг>неохота, некрасиво, долго муторно
зиг>а что никак с этой транзакцией поисхитряться не получится?

Это называется "очистка тестового окружения". Ну не обязательно "грохать", можно просто таблицы почистить. В тестовом классе это можно прописать один раз для всех тестов.
Программа – это мысли спрессованные в код
Re[4]: транзакции и тестирование
От: dimgel Россия https://github.com/dimgel
Дата: 26.01.15 13:38
Оценка: +1
Здравствуйте, Qulac, Вы писали:

Q>Ну не обязательно "грохать", можно просто таблицы почистить.


Ненадёжно/неуниверсально. Вдруг тестируемый код сам таблицы/индексы/а то и вообще хранимки создаёт? А вдруг там хитрые FK-зависимости между таблицами, что запаришься их удалять? Истинно говорю, ничто не сравнится с "drop database" по простоте и чистоте эксперимента! =)
Re: транзакции и тестирование
От: . Великобритания  
Дата: 26.01.15 13:49
Оценка:
Здравствуйте, зиг, Вы писали:

зиг>я согласна даже на чтонибудь типа рефлексией изменять уровень пропагации этого метода ТОЛЬКО для тестирования. но чтоб в продакшне был код без изменений. такое возможно?

Можно создать тестовый Spring контекст, который тупо игнорирует все Transactional-атрибуты и управлять транзакциями самому, вручную, внутри теста.
Очевидно, надо будет учесть, что такой тест не сможет тестировать всё, т.к. явно может существовать бизнес-логика, которая требует наличие таких атрибуов (unhappy paths, когда что-то кидает исключение и надо что-то закоммитить, а что-то не коммитить). Но для этого можно делать другие тесты, которые воспроизводят контекст более точно...
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 26.01.2015 13:53 · . Предыдущая версия . Еще …
Отредактировано 26.01.2015 13:52 · . Предыдущая версия .
Отредактировано 26.01.2015 13:51 · . Предыдущая версия .
Re[2]: транзакции и тестирование
От: зиг Украина  
Дата: 26.01.15 13:59
Оценка:
Здравствуйте, ., Вы писали:

.>Здравствуйте, зиг, Вы писали:


зиг>>я согласна даже на чтонибудь типа рефлексией изменять уровень пропагации этого метода ТОЛЬКО для тестирования. но чтоб в продакшне был код без изменений. такое возможно?

.>Можно создать тестовый Spring контекст, который тупо игнорирует все Transactional-атрибуты и управлять транзакциями самому, вручную, внутри теста.
.>Очевидно, надо будет учесть, что такой тест не сможет тестировать всё, т.к. явно может существовать бизнес-логика, которая требует наличие таких атрибуов (unhappy paths, когда что-то кидает исключение и надо что-то закоммитить, а что-то не коммитить). Но для этого можно делать другие тесты, которые воспроизводят контекст более точно...

имеешь ввиду не создавать txManager в текущем тестовом спринговом контексте, соотственно все транзакшнл аннотации будут игнорироваться?
а транзакцию в тесте сздавать самим вручную вначале и роллбечить в конце?помоему это не будет работать
Re[2]: транзакции и тестирование
От: andyag  
Дата: 26.01.15 14:09
Оценка:
Здравствуйте, dimgel, Вы писали:

D>Лично я перед каждым тестом базу пересоздаю (у меня под это дело отдельный экземпляр SQL-сервера крутится с базой в tmpfs — т.е. в RAM). Так что никаких роллбэков-хэков мне не надо, и с этим подходом я могу даже selenium-тесты гонять на задеплоенном приложении, в которое уж точно rollback не подсунешь.


Про рамдиск решение суперское. Если не секрет, сколько у вас тестов, за сколько проходят на рамдиске, за сколько на обычном HDD?
Re[3]: транзакции и тестирование
От: dimgel Россия https://github.com/dimgel
Дата: 26.01.15 14:26
Оценка:
Здравствуйте, andyag, Вы писали:

A>Если не секрет, сколько у вас тестов, за сколько проходят на рамдиске, за сколько на обычном HDD?


Да вот поди теперь вспомни два-три года спустя. Помню только что за минуту всё отрабатывало.
Re[3]: транзакции и тестирование
От: . Великобритания  
Дата: 26.01.15 18:20
Оценка: 6 (1)
Здравствуйте, зиг, Вы писали:

зиг>>>я согласна даже на чтонибудь типа рефлексией изменять уровень пропагации этого метода ТОЛЬКО для тестирования. но чтоб в продакшне был код без изменений. такое возможно?

.>>Можно создать тестовый Spring контекст, который тупо игнорирует все Transactional-атрибуты и управлять транзакциями самому, вручную, внутри теста.
.>>Очевидно, надо будет учесть, что такой тест не сможет тестировать всё, т.к. явно может существовать бизнес-логика, которая требует наличие таких атрибуов (unhappy paths, когда что-то кидает исключение и надо что-то закоммитить, а что-то не коммитить). Но для этого можно делать другие тесты, которые воспроизводят контекст более точно...

зиг>имеешь ввиду не создавать txManager в текущем тестовом спринговом контексте, соотственно все транзакшнл аннотации будут игнорироваться?

зиг>а транзакцию в тесте сздавать самим вручную вначале и роллбечить в конце?помоему это не будет работать
Spring контекст где-то содержит код (тег <tx:annotation-driven>), который проверяет наличие @Transactional на бинах контекста и создаёт прокси-объекты, которые шлют соответствующие команды txManager-у.
Вот это тебе надо выбросить из тестового конфига и послать команду txManager-у самому. В setUp методе на начало транзации (getTransaction) и tearDown на откат (rollback).

What could possibly go wrong.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 26.01.2015 18:22 · . Предыдущая версия .
Re[3]: транзакции и тестирование
От: . Великобритания  
Дата: 26.01.15 18:21
Оценка:
Здравствуйте, andyag, Вы писали:

D>>Лично я перед каждым тестом базу пересоздаю (у меня под это дело отдельный экземпляр SQL-сервера крутится с базой в tmpfs — т.е. в RAM). Так что никаких роллбэков-хэков мне не надо, и с этим подходом я могу даже selenium-тесты гонять на задеплоенном приложении, в которое уж точно rollback не подсунешь.


A>Про рамдиск решение суперское. Если не секрет, сколько у вас тестов, за сколько проходят на рамдиске, за сколько на обычном HDD?

А насколько оно актуально в наступившей эпохе SSD?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[4]: транзакции и тестирование
От: dimgel Россия https://github.com/dimgel
Дата: 26.01.15 18:34
Оценка:
Здравствуйте, ., Вы писали:

A>>Про рамдиск решение суперское.

.>А насколько оно актуально в наступившей эпохе SSD?

Раза в 1.2-1.5 ЕМНИП. Ну и SSD штука не вечная, постоянно его мучать — нехорошо.
Re[4]: транзакции и тестирование
От: зиг Украина  
Дата: 26.01.15 21:25
Оценка:
Здравствуйте, ., Вы писали:

зиг>>имеешь ввиду не создавать txManager в текущем тестовом спринговом контексте, соотственно все транзакшнл аннотации будут игнорироваться?

зиг>>а транзакцию в тесте сздавать самим вручную вначале и роллбечить в конце?помоему это не будет работать
.>Spring контекст где-то содержит код (тег <tx:annotation-driven>), который проверяет наличие @Transactional на бинах контекста и создаёт прокси-объекты, которые шлют соответствующие команды txManager-у.
.>Вот это тебе надо выбросить из тестового конфига и послать команду txManager-у самому. В setUp методе на начало транзации (getTransaction) и tearDown на откат (rollback).

супер, все сработало, странно чо это я сама не догадалась!!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.