How to test domain validation in unit test cases

Posted By : Shiv Kumar | 19-Jun-2015

Get started with unit test case, the first thing to test is domain - the very basic and important building block for entire development process.

During domain unit testing, the main focus is on constraints validation.

Domain classes are tested by using DomainClassUnitTestMixin or the HibernateTestMixin.

 

Domain to test :

class User {
	String username
	String password
	
	static constraints = {
		username (nullable: false,blank: false, unique: true, email: true, maxSize:60)
		description (blank: false, minSize: 10, maxSize:600)
	}
}

 

Here I am discussing two ways of domain constraints validation testing by using GrailsUnitTestMixin:

 

Way 1 : By using mockForConstraintsTests

GrailsUnitTestMixin provides a method called mockForConstraintsTests used to mock validation support for classes.

mockForConstraintsTests makes the testing task easy by changing the behavior of the errors object and domainClass.errors[field] gives us the name of failed constraint.

If we dont use mockForConstraintsTests, the validation errors are of type org.springframework.validation.FieldError object like :

Property [{0}] of class [{1}] with value [{2}] must be unique
Property [{0}] of class [{1}] with value [{2}] exceeds the maximum size of [{3}]

 

Test case :

class UserSpec extends Specification {
def setup {}
def cleanup() {}

@Unroll
def "test validation on username for the error : #type"(){
	given :
	  mockForConstraintsTests User
	  User user = new User(username : '[email protected]',description: 'test description').save(flush :true)	

	when :
	  User testUser = new User(username : value)
	  if(type == 'unique') 
	  mockForConstraintsTests(User, [testUser, user])  // check for the uniqueness between two user objects

       	then :
  	  !testUser.validate()
	  testUser.hasErrors()
	  testUser.errors['username'] == type  //mockForConstraintsTests gives the name of failed constraint

  	where:
 	  type|value
 	  'maxSize'|'L'*61+'@gmail.com'
 	  'email'|'abc'
	  null|'[email protected]'
	  'unique'|"[email protected]"
}
}

 

Way 2: By defining custom abstract class and extend it instead of Specification.

Create your own abstract class like :

import spock.lang.Specification

abstract class ConstraintUnitSpec extends Specification {
    String getLongString(Integer length) {
        'b' * length
    }

    String getEmail(Boolean valid) {
        valid ? "[email protected]" : "testemail@g"
    }

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

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

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

Now you have to modify the above test case little bit like:

class UserSpec extends ConstraintUnitSpec {   // UserSpec extends ConstraintUnitSpec instead of Specification as done earlier
def setup {}
def cleanup() {}

@Unroll
def "test validation on #field for the error : #error"(){
	given :
	  User user = new User(username : '[email protected]',password: 'Admin@1234').save(flush :true)	

	when :
	  User testUser = new User()
	  user."${field}" = value
	 	

       	then :
  	   validateConstraints(testUser, field, error)

  	where:
 	  error| value | field
	  'nullable'| null | 'username'
	  'blank'| '' | 'username'
 	  'maxSize.exceeded' | getLongString(61)+'@gmail.com' | 'username'
 	  'email'| getEmail(false)  | 'username'
	  'valid' | getEmail(true) | 'username'
	  'nullable' | null | 'description'
 	  'blank' | '' | 'description'
          'minSize.notmet' | getLongString(8) | 'description'
          'maxSize.exceeded' | getLongString(601) | 'description'
}
}

The main concept of abstract class is to make the things reusable through out all the test cases and define custom getter for email and other things which maintain the code neat and clean.

Enjoy the stuff.

Thanks

Shiv Kumar

Related Tags

About Author

Author Image
Shiv Kumar

Shiv is an experienced Java Developer with a strong background in multiple technologies. He specializes in defining system architectures to ensure reliable and resilient solutions. He possesses a comprehensive understanding of the latest technologies and has hands-on experience in Core Java, Spring Boot, Hibernate, Apache Kafka messaging queue, Redis, as well as relational databases like MySQL and PostgreSQL, and non-relational databases like MongoDB. He excels in API implementations, Microservices, Web Services development, testing, and deployments. Shiv actively contributes to code enhancements and consistently delivers valuable contributions to various client projects, including Fabtrack, Pando, Pandojo, Digikam, WhatsApp Integration, Croniz, Punchin Application, Script TV, Bhaasha, and more. He demonstrates strong analytical skills and a creative mindset. In addition, he has a passion for reading books and exploring new technologies and innovations.

Request for Proposal

Name is required

Comment is required

Sending message..