Тестирование Grails/Spock... возникла непредвиденная ошибка

Использование spock для модульного тестирования объекта команды. У меня есть строка в объекте команды..

какой-то код..

   } else { 
      if ((val && obj.part) && obj.transactionType.transactionIsATransfer()) { 
         println "obj.part .. class is ${obj.part.getClass()} .. serial is    ${val.getClass()}" 
         if(! isAValidPartSerialCombo(obj.part,val))  <-- line 79  
             return 'com.myStuff.TransactionDetailCommand.serialReference.not.for.part' 
    } 
.. 

def isAValidPartSerialCombo {part, serialReference -> 
        return InventoryMaster.hasPartandSerial(part,serialReference) 
} 

У меня есть модульный тест, в котором я издеваюсь над зависимостью

def obj = new TransactionDetailCommand(transactionType: new TransactionType(type: 'Transfer', requireSerial: true), 
              serialReference: 'AAA', part: new Part(partNumber: 'AAA')) 

      obj.metaClass.isAValidPartSerialCombo = {a,b -> false}

  and: "we try to validate the transaction " 
      obj.validate() 

  then: "we get an error on the transaction for the 'serialReference' property" 
      obj.errors['serialReference'] 

что мне выдает ошибку..

java.lang.IllegalArgumentException: object is not an instance of declaring class 
        at com.vantec.TransactionDetailCommand._clinit__closure1_closure7(TransactionDetailCommand.groovy:90) 
        at grails.test.MockUtils.addValidateMethod_closure87_closure114(MockUtils.groovy:1035) 
        at grails.test.MockUtils.addValidateMethod_closure87(MockUtils.groovy:1031) 
        at grails.test.MockUtils.addValidateMethod_closure88(MockUtils.groovy:1065) 
        at com.myStuff.transaction.TransactionDetailCommandSpec.Ensure that for issues / transfer transactions then serial/part numbers are required to match .. (TransactionDetailCommandSpec.groovy:79) 

Однако, если я создаю отдельный фиктивный тест, он работает без проблем.

def "A simple test  .. "(){ 
    when: 
        def obj = new TransactionDetailCommand() 
        obj.metaClass.isAValidPartSerialCombo = {a,b -> false} 

    then: 'we get a false ..' 
        !obj.isAValidPartSerialCombo(new Part(),"AAA") 
} 

Кто-нибудь может пролить свет??

Спасибо

Полный тест...

  def "Ensure that for issues / transfer transactions then serial/part numbers are required to match .. "(){

          when: "The transaction type indicates a transfer and we supply a serial number and a part .."

              def obj = new TransactionDetailCommand(transactionType: new TransactionType(type: 'Transfer', requireSerial: true),
                      serialReference: '12345', part: new Part(partNumber: 'PartA'))

              obj.metaClass.isAValidPartSerialCombo = {a,b -> false}

          and: "we try to validate the transaction "
              obj.validate()

          then: "we get an error on the transaction for the 'serialReference' property"
              obj.errors['serialReference']

          and: "the error is the correct one .."
              'com.myStuff.TransactionDetailCommand.serialReference.not.for.part' == obj.errors['serialReference']

    }

и ограничение, которое я тестирую..

serialReference nullable: true, validator: { val, obj ->

           println "One .. "
           if ((val == null || val.toString().isEmpty()) && obj.transactionType.requireSerial) {
                 println "Two .. "
                return 'com.myStuff.TransactionDetailCommand.serialReference.required'
            } else {
                 println "Three .. "
                if ((val && obj.part) && obj.transactionType.transactionIsATransfer()) {
                    println "Four ..."
                    if(! isAValidPartSerialCombo(obj.part, val)){
                        println("Five .. ")
                        return  'com.myStuff.TransactionDetailCommand.serialReference.not.for.part'
                    }
                }
            }

            return 'oops'
        }



 def isAValidPartSerialCombo = {part, serialReference ->
        println "Six .."
        // return InventoryMaster.hasPartandSerial(part,serialReference)
        return true
    }

Println просто для того, чтобы я мог видеть, куда идет код.


person user566311    schedule 06.05.2014    source источник
comment
Какая строка имеет номер 79 в TransactionDetailCommandSpec.groovy?   -  person Fran García    schedule 06.05.2014
comment
Извините .. Это obj.validate() .. который не работает в строке, которую я пометил как 79 в первом блоке кода ..   -  person user566311    schedule 06.05.2014
comment
Можете ли вы сделать isAValidPartSerialCombo статическим (поскольку валидатор находится в статическом контексте) и использовать obj.metaClass.'static'.isAValidPartSerialCombo? В противном случае я бы попробовал переопределить метакласс в классе вместо объекта.   -  person dmahapatro    schedule 06.05.2014
comment
Я сделал это раньше, и это не сработало (см. ниже) .... пока я не изменил вызов в процедуре проверки с if(! isAValidPartSerialCombo(obj.part, val)){ .. на if(! obj.isAValidPartSerialCombo (obj.part, val)){ и теперь это работает!!   -  person user566311    schedule 06.05.2014


Ответы (2)


Не уверен в этом, но стоило бы попробовать издеваться над экземпляром obj после создания экземпляра.

mockDomain(TransactionDetailCommand, [obj])
person Fran García    schedule 06.05.2014
comment
В моей настройке у меня уже есть ..mockForConstraintsTests TransactionDetailCommand .. Думаю, я попробую и рефакторинг isAValidPartSerialCombo .. на статический и смоделирую это .. Я получаю сообщение об ошибке с mockDomain .. - person user566311; 06.05.2014
comment
Только для неудачного метода или всех их - их довольно много! - person user566311; 06.05.2014
comment
Неудачный метод тестирования - person Fran García; 06.05.2014

Попробуйте организовать свой тест таким образом:

def "Ensure that for issues / transfer transactions then serial/part numbers are required to match .. "(){

      given: "The transaction type indicates a transfer and we supply a serial number and a part .."

          def obj = new TransactionDetailCommand(transactionType: new TransactionType(type: 'Transfer', requireSerial: true),
                  serialReference: '12345', part: new Part(partNumber: 'PartA'))

          obj.metaClass.isAValidPartSerialCombo = {a,b -> false}

      when: "we try to validate the transaction "
          obj.validate()

      then: "we get an error on the transaction for the 'serialReference' property"
          obj.errors['serialReference']

      and: "the error is the correct one .."
          'com.myStuff.TransactionDetailCommand.serialReference.not.for.part' == obj.errors['serialReference']

}

поскольку создание объекта и метапрограммирование — все это настроенные действия.

person Fran García    schedule 06.05.2014
comment
Что ж, я видел и пробовал оба подхода, и я думаю, что это действительно зависит от личных предпочтений ... хотя в этом случае ни один из них не работает - я получаю ту же ошибку ... - person user566311; 06.05.2014
comment
Я думаю, что это может быть как-то связано с тем, что это командный объект, и он определяется с помощью @TestFor(TransactionProcessingController). Хотя это единственный тест, с которым у меня возникла проблема - мои другие тесты для командного объекта работают нормально. . - person user566311; 06.05.2014