Search code examples
grailsgroovyspockbeforeupdate

Testing that beforeUpdate or beforeInsert are fired in Grails with Spock


I'm new in Grails and I'm doing some tests but although beforeUpdate and beforeInsert are called in development, my tests say they aren't, what I'm doing wrong?

I'm mocking Cicle and Measurement so I think that when the method save is called, the beforeUpdate or beforeInsert are triggered, but when I run the tests grails answers back saing "Too few invocations for: 1 * cicle.updateCicleValue() (0 invocations)"

So am I using the "when" incorrectly? or save doesn't trigger beforeUpdate and beforeInsert in mock objects?

Please help :)

Cicle.goovy

class Cicle {

String machine
double cicleValue

static hasMany = [measurements:Measurement]

def beforeInsert(){
    if (measurements != null) updateCicleValue()
}

def beforeUpdate(){
    if (measurements != null) updateCicleValue()
}

public void updateCicleValue(){

    double sumCicleValue = 0

    measurements.each{ measurement ->
        sumCicleValue += measurement.cicleValue
    }

    cicleValue = sumCicleValue / measurements.size()
}   
}

CicleSepc.groovy

@TestFor(Cicle)
@Mock([Cicle, Measurement])
class CicleSpec extends Specification {

Measurement mea1    
Measurement mea2    
Cicle cicle


def setup() {
    mea1 = new Measurement(machine: "2-12", cicleValue: 34600)      
    mea2 = new Measurement(machine: "2-12", cicleValue: 17280)      
    cicle = new Cicle(machine: "2-12")

    cicle.addToMeasurements(mea1)
    cicle.addToMeasurements(mea2)       
}

def cleanup() {
}

void "Test updateCicleValue is triggered"(){

    when: "Saving..."
    cicle.save(flush:true)

    then: "updateCicleValue is called once"
    1 * cicle.updateCicleValue()
}
}

Thanks!


Solution

  • //Integration Spec
    import grails.test.spock.IntegrationSpec
    
    class AuthorIntSpec extends IntegrationSpec {
    
        void "test something"() {
            given:
               def author
    
            when:
                Author.withNewSession {
                    author = new Author(name: 'blah').save(flush: true)
                }
    
            then:
                author.name == 'foo'
        }
    }
    
    //Author
    class Author {
        String name
    
        def beforeInsert() {
            this.name = 'foo'
        }
    }
    

    Also note, to use withNewSessionin events if you end up persisting any entity although above simple test would pass without specifying withNewSesion (mentioned for brevity).

    In your use case, there is no mocking involved so testing an interaction is not possible afaik, but you can assert that the value of circleValue has updated after insert (flush), which in turn tests that beforeInsert event is fired appropriately.