Я пытаюсь получить транзакции, работающие в сервисе Grails, но я не получаю ожидаемых результатов. Может ли кто-нибудь сказать мне, что я делаю что-то неправильно, если мои предположения не работают?Сервисные операции Grails
Мой класс домен:
class Account {
static constraints = {
balance(min: 0.00)
}
String companyName
BigDecimal balance = 0.00
Boolean active = true
String toString() {
return "${companyName} : ${balance}"
}
}
Моя служба:
class AccountService {
static transactional = true
def transfer(Account source, Account destination, amount) throws RuntimeException {
if (source.active && destination.active) {
source.balance -= amount
if (!source.save(flush: true)) {
throw new RuntimeException("Could not save source account.")
} else {
destination.balance += amount
if (!destination.save(flush: true)) {
throw new RuntimeException("Could not save destination account.")
}
}
} else {
throw new RuntimeException("Both accounts must be active.")
}
}
def someMethod(Account account) throws RuntimeException {
account.balance = -10.00
println "validated: ${account.validate()}"
if(!account.validate()) {
throw new RuntimeException("Rollback!")
}
}
}
Мой блок тест:. импорт grails.test *
class AccountServiceTests extends GrailsUnitTestCase {
def AccountService
protected void setUp() {
super.setUp()
mockDomain(Account)
AccountService = new AccountService()
}
protected void tearDown() {
super.tearDown()
}
void testTransactional() {
def account = new Account(companyName: "ACME Toy Company", balance: 2000.00, active: true)
def exception = null
try {
AccountService.someMethod(account)
} catch (RuntimeException e) {
exception = e
}
assert exception instanceof RuntimeException
println "exception thrown: ${exception.getMessage()}"
assertEquals 2000.00, account.balance
}
}
Результат:
Testsuite: AccountServiceTests
Tests run: 1, Failures: 1, Errors: 0, Time elapsed: 1.068 sec
------------- Standard Output ---------------
--Output from testTransactional--
validated: false
exception thrown: Rollback!
------------- ---------------- ---------------
------------- Standard Error -----------------
--Output from testTransactional--
------------- ---------------- ---------------
Testcase: testTransactional took 1.066 sec
FAILED
expected:<2000.00> but was:<-10.00>
junit.framework.AssertionFailedError: expected:<2000.00> but was:<-10.00>
at AccountServiceTests.testTransactional(AccountServiceTests.groovy:89)
at _GrailsTest_groovy$_run_closure4.doCall(_GrailsTest_groovy:203)
at _GrailsTest_groovy$_run_closure4.call(_GrailsTest_groovy)
at _GrailsTest_groovy$_run_closure2.doCall(_GrailsTest_groovy:147)
at _GrailsTest_groovy$_run_closure1_closure19.doCall(_GrailsTest_groovy:113)
at _GrailsTest_groovy$_run_closure1.doCall(_GrailsTest_groovy:96)
at TestApp$_run_closure1.doCall(TestApp.groovy:66)
at gant.Gant$_dispatch_closure4.doCall(Gant.groovy:324)
at gant.Gant$_dispatch_closure6.doCall(Gant.groovy:334)
at gant.Gant$_dispatch_closure6.doCall(Gant.groovy)
at gant.Gant.withBuildListeners(Gant.groovy:344)
at gant.Gant.this$2$withBuildListeners(Gant.groovy)
at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)
at gant.Gant.dispatch(Gant.groovy:334)
at gant.Gant.this$2$dispatch(Gant.groovy)
at gant.Gant.invokeMethod(Gant.groovy)
at gant.Gant.processTargets(Gant.groovy:495)
at gant.Gant.processTargets(Gant.groovy:480)
Мои ожидания:
Когда счет дается отрицательный баланс, он не должен подтверждать (что не делает), RuntimeException должен быть выброшен (который он есть), и учетная запись должна откат к предыдущему состоянию (баланс: 2000), где он разваливается.
Что мне здесь не хватает?
Эй, Берт, имеет смысл. Увы, до сих пор не повезло. Он по-прежнему бросает исключение, как должно, но он ничего не скатывает. – Thody
Вот как это работает. Данные экземпляра учетной записи не будут отменены, но это изменение не будет сохранено. Добавьте «def sessionFactory» в поле ввода с зависимостями и добавьте вызов «sessionFactory.currentSession.clear()» и «account = Account.get (account.id)» перед последним assertEquals, чтобы принудительно перезагрузить учетную запись экземпляр, и тест пройдет. –
Простое примечание для людей, использующих это для написания интеграционных тестов для транзакционных сервисов. Интеграционные тесты сами по себе являются транзакционными, поэтому ваша тестируемая служба не будет в новой транзакции. Это может привести к неожиданному поведению.Обходной путь заключается в отключении транзакций в вашем интеграционном тесте (static transactional = false). –