Вопрос

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.

Это было полезно?

Решение

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']
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top