0

The Crux

I am getting the following error in my unit test when calling MyDomainObject.build() via the Build Test Data plugin:

The Exception

            groovy.lang.MissingMethodException: No signature of method: us.maponline.pesticide.PesticideProfile.addToApplicators() is applicable for argument types: (us.maponline.pesticide.PesticideApplicator) values: [us.maponline.pesticide.PesticideApplicator : null]
            Possible solutions: getApplicators()
                at grails.buildtestdata.handler.NullableConstraintHandler.addInstanceToOwningObjectCollection(NullableConstraintHandler.groovy:121)
                at grails.buildtestdata.handler.NullableConstraintHandler.populateDomainProperty(NullableConstraintHandler.groovy:88)
                at grails.buildtestdata.handler.NullableConstraintHandler.handle(NullableConstraintHandler.groovy:17)
                at grails.buildtestdata.DomainInstanceBuilder.createMissingProperty(DomainInstanceBuilder.groovy:187)
                at grails.buildtestdata.DomainInstanceBuilder.populateInstance(DomainInstanceBuilder.groovy:147)
                at grails.buildtestdata.DomainInstanceBuilder.build(DomainInstanceBuilder.groovy:124)
                at grails.buildtestdata.DomainInstanceBuilder.build(DomainInstanceBuilder.groovy:123)
                at grails.buildtestdata.BuildTestDataService$_addBuildMethods_closure1.doCall(BuildTestDataService.groovy:25)
                at us.maponline.pesticide.PesticideLogServiceTests.testSaveLog(PesticideLogServiceTests.groovy:20)
            | Completed 1 unit test, 1 failed in 5289ms

per the stack trace, this is happening within the buildtestdata plugin code. It seems that my class, PesticideApplicator, is null when it is being added to the PesticideProfile class.

How is it possible that the class I'm asking to be built is null when being passed to the PesticideProfile?

Source Code

Test Case

            @TestFor(PesticideLogService)
            @Build([PesticideLog,PesticideApplicator,PesticideProfile])
            class PesticideLogServiceTests
            {
                void testSaveLog() {

                    PesticideApplicator applicator = PesticideApplicator.build()

                    def result = service.createLog(applicator, new Date())

                    result.errors.each {
                        log.info "got an error. field = $it.field, message:$it.defaultMessage, rejected value = $it.rejectedValue "
                    }

                    assert result: 'no result returned'
                    assert result.success: 'save failed'
                    assert result.result instanceof PesticideLog: "result was not PesticideLog"

                    assert applicator.user.pesticideLogs.size() > 0 : 'expected at least on log to be created.'

                }

            }

PesticideProfileLog

            class PesticideProfile
            {

                def User user
                String companyName

                static constraints = {
                }

                static belongsTo = User
                static hasMany = [sites: PesticideSite, applicators: PesticideApplicator]

            }

PesticideApplicator

            class PesticideApplicator
            {

                String firstName
                String lastName
                String company
                PesticideApplicatorLicense licenseType
                Phone phoneNumber

                static belongsTo = [profile:PesticideProfile]

                static constraints = {
                    company blank: false, maxSize: 55
                    firstName blank: false, maxSize: 55
                    lastName blank: false, maxSize: 100
                    phoneNumber nullable: true
                }

                static mapping = {
                    licenseType length: 55
                }

                def getUser(){
                profile?.user
            }

            }

Thanks for all your help!

John Gordon
  • 2,181
  • 5
  • 28
  • 47

1 Answers1

3

The issue is caused by the build test data plugin attempting to set the value of the user in the PesticideApplicator. The problem is that getUser() isn't a field, it's just a utility helper:

   ...
   def getUser(){
     profile?.user
   }
   ...

Removing getUser() from the PesticideApplicator solved the problem.

That said, I'd still like a helper method to access the user (good to not let my code know about the innards of another class). Marking the method @Transient didn't work; the error still appeared. Short of renaming the method, how can I instruct the build test data plugin to ignore this getter?

Thanks!

John Gordon
  • 2,181
  • 5
  • 28
  • 47
  • If it's not a real field that's persisted to the database, but you want it to still have bean get/set semantics within a Grails Domain object, you should add that field to the `static transient` list: http://grails.org/doc/latest/ref/Domain%20Classes/transients.html BuildTestData (and GORM) will then know to ignore it. I'm not familiar with the `@Transient` annotation for grails (it's a hibernate thing not a GORM thing I think), and the grails page doesn't mention it. Is that somewhere else in the grails docs? – Ted Naleid Jun 02 '12 at 04:26
  • Thanks for the info, Ted. You're right, the `static transients` property worked. I also found another solution too (reviewing the generated code from the spring security plugin): `transient String getUser(){profile?.user}`. Either worked fine. – John Gordon Jun 02 '12 at 13:23