We can unit test constraints in domain objects with the mockForConstraintsTests(domainClass)
method. This will add a validate()
method to our domain class. Normally the validate()
is dynamically added to our domain class when we run our Grails application. But with the mockForConstraintsTests(domainClass)
method we can use it without running a complete Grails application.
Suppose we have the following domain class with a lot of constraints defined for the different properties:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | package com.mrhaki.grails.unittest class User { static constraints = { name blank: false, maxSize: 40 , notEqual: 'testEquals' nickName blank: false, unique: true, minSize: 4 , maxSize: 20 , validator: { if (it == 'groovy' ) { [ 'invalid.groovyness' ] } } avatar nullable: true, validator: {val, obj -> if (val != null ) { val != obj.name } } creditCard nullable: true, creditCard: true email nullable: true, email: true, matches: /.*\.nl$/ type nullable: false, inList: [ 'Admin' , 'User' ] points nullable: true, max : 1000 , min : 100 age nullable: true, range: 12 .. 120 blogURL nullable: true, url: true extra nullable: true, size : 4 .. 25 } String name String nickName String avatar String creditCard String email String type Integer points Integer age String blogURL String extra } |
To unit test the constraints we can simply write a unit test class which extends from GrailsUnitTestCase
. Then we must invoke mockForConstraintsTests(User)
so the validate()
method is added to our user
class. Next we can set values for the properties and test if the validation succeeds or fails. We run the tests with the following grails command:
grails test-app -unit |
Here is the code for the unit test class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | package com.mrhaki.grails.unittest import grails.test.* class UserTests extends GrailsUnitTestCase { def user protected void setUp() { super.setUp() // Make sure we can invoke validate() on our User domain object. mockForConstraintsTests(User) // Set up default user, so we can easily test single properties. user = new User(name: 'test' , nickName: 'tester' , type: 'User' ) } /** * class User{ * ... * nickName unique: true * ... * } */ void testUnique() { // Test user to test uniqueness of nickName property. def test = new User(name: 'tester' , nickName: 'tester' , type: 'User' ) mockForConstraintsTests(User, [test]) assertFalse user.validate() assertEquals 'Nickname is not unique.' , 'unique' , user.errors[ 'nickName' ] user = new User(name: 'test' , nickName: 'otherTester' , type: 'User' ) assertTrue user.validate() } /** * class User { * ... * name notEqual: 'testEquals' * ... * } */ void testNotEqual() { user.name = 'testEquals' assertFalse user.validate() assertEquals 'Name is equal to testEquals.' , 'notEqual' , user.errors[ 'name' ] user.name = 'test' assertTrue user.validate() } /** * class User { * ... * name blank: false * nickName blank: false * ... * } */ void testBlank() { user = new User(name: '' , nickName: '' , type: 'Admin' ) assertFalse user.validate() assertEquals 'Name is blank.' , 'blank' , user.errors[ 'name' ] assertEquals 'NickName is blank.' , 'blank' , user.errors[ 'nickName' ] user = new User(name: 'test' , nickName: 'tester' , type: 'User' ) assertTrue user.validate() } /** * class User { * ... * avatar nullable: true * creditCard nullable: true * email nullable: true * type nullable: false * points nullable: true * age nullable: true * blogURL nullable: true * extra nullable: true * ... * } */ void testNullable() { user = new User() assertFalse user.validate() assertEquals 'Name is null.' , 'nullable' , user.errors[ 'name' ] assertEquals 'NickName is null' , 'nullable' , user.errors[ 'nickName' ] assertNull user.errors[ 'avatar' ] assertNull user.errors[ 'creditcard' ] assertNull user.errors[ 'email' ] assertEquals 'Type is null.' , 'nullable' , user.errors[ 'type' ] assertNull user.errors[ 'points' ] assertNull user.errors[ 'age' ] assertNull user.errors[ 'blogURL' ] assertNull user.errors[ 'extra' ] } /** * class User { * ... * nickName minSize: 4 * ... * } */ void testMinSize() { user = new User(name: 'test' , nickName: 'tst' , type: 'User' ) assertFalse user.validate(); assertEquals 'NickName is not minSize 4.' , 'minSize' , user.errors[ 'nickName' ] user.nickName = 'tester' assertTrue user.validate() } /** * class User { * ... * name maxSize: 40 * nickName maxSize: 20 * ... * } */ void testMaxSize() { user.name = 'This name is just way longer than the maxSize argument defines.' user.nickName = 'The nickName is just too long, people will not remember this.' assertFalse user.validate() assertEquals 'Name is too long.' , 'maxSize' , user.errors[ 'name' ] assertEquals 'NickName is too long.' , 'maxSize' , user.errors[ 'nickName' ] user.name = 'Hubert Klein Ikkink' user.nickName = 'mrhaki' assertTrue user.validate() } /** * class User { * ... * email email: true * ... * } */ void testEmail() { user.email = 'test' assertFalse user.validate() assertEquals 'Not a valid email.' , 'email' , user.errors[ 'email' ] user.email = 'valid@country.nl' assertTrue user.validate() } /** * class User { * ... * email matches: /.*\.nl$/ * ... * } */ void testMatches() { user.email = 'test@country.com' assertFalse user.validate() assertEquals "Doesn't end with .nl." , 'matches ', user.errors[' email'] user.email = 'test@country.nl' assertTrue user.validate() } /** * class User { * ... * creditCard creditCard: true * ... * } */ void testCreditCard() { user.creditCard = '1234512' assertFalse user.validate() assertEquals 'Not a valid creditcard#.' , 'creditCard' , user.errors[ 'creditCard' ] user.creditCard = '4417123456789113' assertTrue user.validate() } /** * class User { * ... * type inList: ['Admin', 'User'] * ... * } */ void testInList() { user.type = 'NotValid' assertFalse user.validate() assertEquals 'NotValid not in list for type.' , 'inList' , user.errors[ 'type' ] user.type = 'user' assertFalse user.validate() assertEquals 'inType validator is case sensitive.' , 'inList' , user.errors[ 'type' ] user.type = 'User' assertTrue user.validate() } /** * class User { * ... * points max: 1000 * ... * } */ void testMax() { user.points = 20000 assertFalse user.validate() assertEquals '20000 is above max for points.' , 'max' , user.errors[ 'points' ] user.points = 900 assertTrue user.validate() } /** * class User { * ... * points min: 100 * ... * } */ void testMin() { user.points = 10 assertFalse user.validate() assertEquals '10 is below min for points.' , 'min' , user.errors[ 'points' ] user.points = 210 assertTrue user.validate() } /** * class User { * ... * extra size: 4..25 * ... * } */ void testSize() { user.extra = 'ab' assertFalse user.validate() assertEquals "'ab' size is below 4 for extra." , 'size' , user.errors[ 'extra' ] user.extra = 'This text is too long to be of the correct size.' assertFalse user.validate() assertEquals 'Text is longer than 25 for extra.' , 'size' , user.errors[ 'extra' ] user.extra = 'This is the right length.' assertTrue user.validate() } /** * class User { * ... * age range: 12..120 * ... * } */ void testRange() { user.age = 0 assertFalse user.validate() assertEquals '0 is below range for age.' , 'range' , user.errors[ 'age' ] user.age = 200 assertFalse user.validate() assertEquals '200 is above range for age.' , 'range' , user.errors[ 'age' ] user.age = 40 assertTrue user.validate() } /** * class User { * ... * blogURL url: true * ... * } */ void testURL() { user.blogURL = 'invalid-url' assertFalse user.validate() assertEquals "'invalid-url' is not valid." , 'url' , user.errors[ 'blogURL' ] user.blogURL = 'http://www.mrhaki.com' assertTrue user.validate() } /** * class User { * ... * nickName validator: { * if (it == 'groovy') { * ['invalid.groovyness'] * } * } * avatar validator: {val, obj -> * if (val != null) { * val != obj.name * } * } * ... * } */ void testCustomValidator() { user.avatar = 'test' assertFalse user.validate() assertEquals "'test' is the same as name." , 'validator' , user.errors[ 'avatar' ] user.avatar = 'avatar-test' assertTrue user.validate() // Test custom error key. user.nickName = 'groovy' assertFalse user.validate() assertEquals "'groovy' not allowed as nickName." , 'invalid.groovyness' , user.errors[ 'nickName' ] user.nickName = 'tester' assertTrue user.validate() } } |