Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disabling a validation constraint in grails command object for unit testing (with Spock)

I'm trying to write some unit tests for Command object validations. When my command object has many fields with many validation rules, setting up the command object for each test case gets too verbose and repetitive.

Say I have this command object:

class MemberCommand {
    String title
    String name
    String phone
    static constraints = {
        title(blank: false, inList: ["Mr", "Mrs", "Miss", "Ms"])
        name(blank: false, maxSize:25)
        phone(blank: false, matches: /\d{8}/)
    }
}

I want to test this by doing something like this:

class ValidationTitle extends UnitSpec {
    def "title must be one of Mr, Mrs, Miss, Ms"() {
        setup:
        def memberCommand = new MemberCommand()
        // I don't want to do:
        // memberCommand.name = "Spock" 
        // memberCommand.phone = "99998888"
        // Instead, I want to disable other constraints, except the one for title
        mockForConstraintsTests MemberCommand, [memberCommand]

        when:
        memberCommand.title = t

        then:
        memberCommand.validate() == result

        where:
        t << ["Mr", "Mrs", "Miss", "Ms", "Dr", ""]
        result << [true, true, true, true, false, false]
    }
}

This test will fail because when memberCommand.validate() is called, all constraints will be used, and result in validation error even in the case when the title, "Mr" is being tested. I could set the name and phone for this one test, but then, I'll need to set title and phone when I'm testing for name validation, and title and name when testing for phone validation. You can imagine how this gets more annoying when there are more fields to the command objects with more complicated rules.

Is there any way of disabling constraints in unit testing (with Spock) in grails?

If not, any other suggestions for situations like this?

Thank you.

like image 642
tim_wonil Avatar asked Oct 30 '25 03:10

tim_wonil


1 Answers

You can't disable specific constraint validations. But, you can either provide valid values for the rest of your attributes, or check for errors in the title attribute in particular.

In the first case, you simply create a map with default (and valid) attributes and initialize your command from them:

def validAttributes = [ title: 'Mr', name: 'Spock', phone: '99998888' ]

def "title must be one of Mr, Mrs, Miss, Ms"() {
    setup:
    def memberCommand = new MemberCommand(validAttributes)
    mockForConstraintsTests MemberCommand, [memberCommand]

    when:
    memberCommand.title = t

    then:
    memberCommand.validate() == result

    where:
    t << ["Mr", "Mrs", "Miss", "Ms", "Dr", ""]
    result << [true, true, true, true, false, false]
}

It's also good practice to have a "baseline" case that validates (I always follow this pattern in my tests). It expresses your basic assumptions about your validations.

For the other possibility, you'd do:

def "title must be one of Mr, Mrs, Miss, Ms"() {
    setup:
    def memberCommand = new MemberCommand()
    mockForConstraintsTests MemberCommand, [memberCommand]

    when:
    memberCommand.title = t
    memberCommand.validate()

    then:
    memberCommand.errors['title'] == result

    where:
    t << ["Mr", "Mrs", "Miss", "Ms", "Dr", ""]
    result << [null, null, null, null, 'not.inList', 'not.inList']
}
like image 166
Gustavo Giráldez Avatar answered Nov 01 '25 08:11

Gustavo Giráldez