Операции с Grails - PullRequest
       19

Операции с Grails

1 голос
/ 15 января 2010

Я пытаюсь заставить транзакции работать в сервисе 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) , где он разваливается.

Что мне здесь не хватает?

Ответы [ 3 ]

4 голосов
/ 15 января 2010

Модульные тесты - это просто классы Groovy или Java, поэтому контекст приложения Spring отсутствует и, следовательно, нет поддержки транзакций. Вы должны были бы посмеяться над этим для юнит-теста, но это не будет проверкой транзакционности, а только качеством макетов. Преобразуйте это в интеграционный тест и не вызывайте новое в службе, используйте внедрение зависимостей:

class AccountServiceTests extends GroovyTestCase {

  def AccountService

  void testTransactional() {
    def account = new Account(companyName: "ACME Toy Company", balance: 2000.00,
                              active: true)
    account.save()
    assertFalse account.hasErrors()

    String message = shouldFail(RuntimeException) {
      AccountService.someMethod(account)
    }

    println "exception thrown: $message"

    assertEquals 2000.00, account.balance
  }
}

Обратите внимание, что фактическое исключение может быть исключением-оболочкой, а выброшенное исключение является его причиной.

1 голос
/ 16 января 2010

Я попробовал код, но вижу ту же проблему в интеграционном тесте. Я использовал Grails 1.2

Согласно Jira GRAILS-3765 это известная проблема, которая все еще остается открытой. (Я не уверен, почему он говорит «влияет на версию 1.0.4» только тогда, когда 1.1.x давно отсутствует).

Исходя из этих моментов, я думаю, что это ошибка в Grails. В записке Jira есть обходной путь, но я не пробовал. Однако, в зависимости от проблемы, он все равно будет работать при запуске приложения; это можно подтвердить вручную.

0 голосов
/ 16 января 2010

Какую версию Grails вы используете? В версии 1.1.1 есть ошибка, в которой транзакция = true не работает должным образом.

...