class Book { String title static constraints = { title minSize: 10 } } @TestFor(Book) class BookTests { void testShortTitle() { domain.title = 'too short' assert !domain.validate() assert 'minSize.notmet' == domain.errors.getFieldError('title').code } }
It would be nice if the last assert would allow the shorthand syntax to lookup the title field error code (see also GRAILS-8415):
assert 'minSize' == domain.errors.title
However, that will not work:
--Output from testShortTitle-- | Failure: testShortTitle(bookstore.BookTests) | groovy.lang.MissingPropertyException: No such property: title for class: org.grails.datastore.mapping.validation.ValidationErrors
Why? The errors property is of type org.grails.datastore.mapping.validation.ValidationErrors (or grails.validation.ValidationErrors). This type does support the subscript operator though, so it can be slightly shorter:
assert 'minSize.notmet' == domain.errors['title'].code
But it still needs to read the code property of FieldError, and this code does not match the constraint name.
If we look a bit further at other subclasses of org.springframework.validation.BeanPropertyBindingResult, we see that the shorthand syntax is available in org.codehaus.groovy.grails.plugins.testing.GrailsMockErrors, and it translates the codes to constraint names, so 'minSize' can be used instead of 'minSize.notmet'.
To use GrailsMockErrors, we can call mockForConstraintsTests from our test class. For example, we can call it once for the domain class to mock all instances like this:
@TestFor(Book) class BookTests { @Before void setUp() { mockForConstraintsTests(Book) } void testShortTitle() { domain.title = 'too short' assert !domain.validate() assert 'minSize' == domain.errors.title } }
The mocking will prepare the Book class, including the errors field, and make the shorthand syntax available.
It's also possible to instantiate our own Book instances instead of using "domain", and test them in the same way. The advantage is that we can use the property map constructor, although it also helps to use the 'with' method on the domain field:
@TestFor(Book) class BookTests { @Before void setUp() { mockForConstraintsTests(Book) } void testShortTitle() { domain.with { title = 'too short' assert !validate() assert 'minSize' == errors.title } } }
No comments:
Post a Comment