Grails: how to save value on the transient field during the test unit with Spock?

advertisements

In order to test a domain class, which has a transient field, I tried to put a value for that field by the two following ways:

Requirement requirement = new Requirement(linearProduct: linearProduct, periodIndexes: [1,2,3])
requirement.periodIndexes = [1,2,3]

Both of them made the field appear as null object when getting into the tested function.

My question is how to make the values pass although it transient field?


Transient properties are bindable:false by default. If you want the periodIndexes field to be bindable with named arguments you have to be explicit about that:

class Requirement {
    transient List periodIndexes

    static constraints = {
        periodIndexes bindable: true
    }
}

It isn't clear why your requirement.periodIndexes = [1,2,3] results in null. It shouldn't. If you can show a more complete test I can help you with that.

EDIT:

As an example...

A domain class:

// grails-app/domain/demo/Widget.groovy
package demo

class Widget {
    String name
    transient List firstTransientList
    transient List secondTransientList

    static constraints = {
        secondTransientList bindable: true
    }
}

This test will pass:

// test/unit/demo/WidgetSpec.groovy
package demo

import grails.test.mixin.TestFor
import spock.lang.Specification

@TestFor(Widget)
class WidgetSpec extends Specification {

    void "test binding to transient fields"() {
        when: 'binding to transient properties using named arguments'
        def widget = new Widget(firstTransientList: [1, 2, 3],
                                secondTransientList: [4, 5, 6])

        then: 'by default transient fields are not bindable'
        widget.firstTransientList == null

        and: 'transient fields configured with bindable:true are bindable'
        widget.secondTransientList == [4, 5, 6]

        when: 'a value is assigned directly to a transient property'
        widget.firstTransientList = [7, 8, 9]

        then: 'the assignment succeeds'
        widget.firstTransientList == [7, 8, 9]
    }
}

You haven't said which version of Grails you are using. Some of this behavior changed in the 2.3.x line. The test above should pass with recent versions of Grails.

ANOTHER EDIT (to answer a question in a comment below):

The transient properties may be defined without the transient keyword but instead using the transients property, as shown below:

// grails-app/domain/demo/Widget.groovy
package demo

class Widget {
    String name
    List firstTransientList
    List secondTransientList

    static transients = ['firstTransientList', 'secondTransientList']

    static constraints = {
        secondTransientList bindable: true
    }
}