在grails应用程序中使用spock验证空白约束的问题

时间:2013-11-07 08:26:57

标签: grails groovy spock

我有一个版本为2.3.1的grails应用程序和BuildConfig.groovy

中的下一个配置
   dependencies {
        ...
        ..
        .
        test "org.spockframework:spock-grails-support:0.7-groovy-2.0"
    }
    plugins {
        test(":spock:0.7") {
            exclude "spock-grails-support"
        }

我有下一个域类:

class Draft {
    def grailsApplication

    String name
    String subject
    String content

    static constraints = {
        name unique: true, blank: false
        subject blank: false
    }

    static mapping = {
        content type: 'text'
    }
}

我发现这篇文章Testing Domain Constraints Using Grails 2.x & Spock 0.7有一个测试域类约束的有趣方法。

我有一个spock测试:

import spock.lang.Specification

abstract class ConstraintUnitSpec extends Specification {

    String getLongString(Integer length) {
        'a' * length
    }

    String getEmail(Boolean valid) {
        valid ? "dexter@miamipd.gov" : "dexterm@m"
    }

    String getUrl(Boolean valid) {
        valid ? "http://www.google.com" : "http:/ww.helloworld.com"
    }

    String getCreditCard(Boolean valid) {
        valid ? "4111111111111111" : "41014"
    }

    void validateConstraints(obj, field, error) {
        println "Draft name: " + obj.name 
        def validated = obj.validate()
        if (error && error != 'valid') {
            assert !validated
            assert obj.errors[field]
            assert error == obj.errors[field]
        } else {
            assert !obj.errors[field]
        }
    }
}

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

@TestFor(Draft)
class DraftSpec extends ConstraintUnitSpec {
     def setup() {
        mockForConstraintsTests(Draft, [new Draft(name: 'unique')])
     }

     @Unroll("test draft all constraints #field is #error")
     def "test draft all constraints"() {
          when:
          def obj = new Draft("$field": val)

          then:
          validateConstraints(obj, field, error)

          where:
          error                  | field        | val
          'nullable'             | 'name'       | null
          'nullable'             | 'subject'    | null
          'nullable'             | 'content'    | null
          'unique'               | 'name'       | 'unique'
          'valid'                | 'name'       | 'valid name'
          'valid'                | 'subject'    | 'valid subject'
          'blank'                | 'name'       | ''
          'blank'                | 'subject'    | ''
   }
}

两个blank约束中的测试失败:

Draft name: null
| Failure:  test draft all constraints subject is blank(DraftSpec)
|  Condition not satisfied:

error == obj.errors[field]
|     |  |   |     ||
blank |  |   |     |subject
      |  |   |     nullable
      |  |   org.codehaus.groovy.grails.plugins.testing.GrailsMockErrors: 3 errors
      |  |   Field error in object 'Draft' on field 'name': rejected value [null]; codes [Draft.name.nullable.error.Draft.name,Draft.name.nullable.error.name,Draft.name.nullable.error.java.lang.String,Draft.name.nullable.error,draft.name.nullable.error.Draft.name,draft.name.nullable.error.name,draft.name.nullable.error.java.lang.String,draft.name.nullable.error,Draft.name.nullable.Draft.name,Draft.name.nullable.name,Draft.name.nullable.java.lang.String,Draft.name.nullable,draft.name.nullable.Draft.name,draft.name.nullable.name,draft.name.nullable.java.lang.String,draft.name.nullable,nullable.Draft.name,nullable.name,nullable.java.lang.String,nullable]; arguments [name,class Draft]; default message [Property [{0}] of class [{1}] cannot be null]
      |  |   Field error in object 'Draft' on field 'subject': rejected value [null]; codes [Draft.subject.nullable.error.Draft.subject,Draft.subject.nullable.error.subject,Draft.subject.nullable.error.java.lang.String,Draft.subject.nullable.error,draft.subject.nullable.error.Draft.subject,draft.subject.nullable.error.subject,draft.subject.nullable.error.java.lang.String,draft.subject.nullable.error,Draft.subject.nullable.Draft.subject,Draft.subject.nullable.subject,Draft.subject.nullable.java.lang.String,Draft.subject.nullable,draft.subject.nullable.Draft.subject,draft.subject.nullable.subject,draft.subject.nullable.java.lang.String,draft.subject.nullable,nullable.Draft.subject,nullable.subject,nullable.java.lang.String,nullable]; arguments [subject,class Draft]; default message [Property [{0}] of class [{1}] cannot be null]
      |  |   Field error in object 'Draft' on field 'content': rejected value [null]; codes [Draft.content.nullable.error.Draft.content,Draft.content.nullable.error.content,Draft.content.nullable.error.java.lang.String,Draft.content.nullable.error,draft.content.nullable.error.Draft.content,draft.content.nullable.error.content,draft.content.nullable.error.java.lang.String,draft.content.nullable.error,Draft.content.nullable.Draft.content,Draft.content.nullable.content,Draft.content.nullable.java.lang.String,Draft.content.nullable,draft.content.nullable.Draft.content,draft.content.nullable.content,draft.content.nullable.java.lang.String,draft.content.nullable,nullable.Draft.content,nullable.content,nullable.java.lang.String,nullable]; arguments [content,class Draft]; default message [Property [{0}] of class [{1}] cannot be null]
      |  Draft : (unsaved)
      false
      6 differences (25% similarity)
      (b-)l(-)a(nk-)
      (nu)l(l)a(ble)

    at ConstraintUnitSpec.validateConstraints(ConstraintUnitSpec.groovy:29)
    at DraftSpec.test draft all constraints(DraftSpec.groovy:18)
| Completed 8 spock tests, 2 failed in 0m 6s
| Tests FAILED  - view reports in /Users/sdelamo/Documents/Developer/bitbucket/concertados-webapp/target/test-reports

问题

当我将Draft作为值

时,

name的{​​{1}}字段设置为空

我错过了什么?提前谢谢。

SIMPLE TEST也失败了

''

这是错误:

def "test blank constraints"() {
          when: 'the name and subjects are blank'
          def d = new Draft(name: '', subject:'')

          then: 'the validation should fail with blank errors'
          !d.validate()
          'blank' == d.errors["name"]
          'blank' == d.errors["subject"]
   }

2 个答案:

答案 0 :(得分:7)

Time_yates指出了这个问题:

http://grails.org/doc/latest/ref/Constraints/nullable.html

  

表单提交产生的​​Web请求将包含空字符串,   对于没有值的输入字段,不为null。请记住这一点   将mass属性绑定到不可为空的属性。该   默认行为是空字符串不会验证   nullable:false,因为数据绑定器会将空字符串转换为   空值。这包括空字符串和空字符串。一个空白的字符串是   任何字符串,以使trim()方法返回一个空字符串。至   关闭空字符串的转换为null设置   grails.databinding.convertEmptyStringsToNull属性为false   Config.groovy中。有关数据的更多详细信息,请参阅数据绑定部分   结合。

答案 1 :(得分:0)

对于Grails 2.3.9,此测试突出显示空白约束的问题,即使使用上述配置设置(在then语句中检查)。

无法追查问题。 BlankConstraint不检查null属性,并且blank和nullable约束都是可否决的,因此如果一个失败,则忽略所有其他约束。

正在测试的课程:

package test

class TestVetoableConstraints {
    String nullableAndBlank
    String nullableAndNotBlank
    String notNullableAndBlank
    String notNullableAndNotBlank

    static constraints = {
    nullableAndBlank(nullable:true, blank:true)
    nullableAndNotBlank(nullable:true, blank:false)
    notNullableAndBlank(nullable:false, blank:true)
    notNullableAndNotBlank(nullable:false, blank:false)
    }
}

<强>测试

package test

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

@TestFor(TestVetoableConstraints)
class TestVetoableConstraintsSpec extends Specification {
    def config = Holders.config

    void "test nullable and blank constraints" (error, field, val) {
        when: 
            mockForConstraintsTests(TestVetoableConstraints)
            def obj = new TestVetoableConstraints("$field": val)

        then: 
// These are set to ensure that an empty string isn't trimmed and converted to null
            false == config.grails.databinding.convertEmptyStringsToNull
            false == config.grails.databinding.trimStrings
            validateConstraints(obj, field, error)

        where:
            error                  | field                      | val
            'valid'                | 'nullableAndBlank'         | null
            'valid'                | 'nullableAndBlank'         | ''
            'valid'                | 'nullableAndBlank'         | 'Good String'
            'valid'                | 'nullableAndNotBlank'      | null
// The next test should return blank, but actually fails on "assert obj.errors[field]" which is null
            'blank'                | 'nullableAndNotBlank'      | ''
            'valid'                | 'nullableAndNotBlank'      | 'Good String'
            'nullable'             | 'notNullableAndBlank'      | null
// The next test should be valid, but actually fails on "assert !obj.errors[field]" which returns 'nullable'
            'valid'                | 'notNullableAndBlank'      | ''
            'valid'                | 'notNullableAndBlank'      | 'Good String'
            'nullable'             | 'notNullableAndNotBlank'   | null
// The next test should return blank, but actually fails on "assert error == obj.errors[field]" because it returns 'nullable'
            'blank'                | 'notNullableAndNotBlank'   | ''
            'valid'                | 'notNullableAndNotBlank'   | 'Good String'
    }

    private void validateConstraints(obj, field, error) {
       def validated = obj.validate()
       if (error && error != 'valid') {
           assert !validated
           assert obj.errors[field]
           assert error == obj.errors[field]
       } else {
           assert !obj.errors[field]
       }
   }
}