Introduction to data driven spock testing
Posted By : Shiv Kumar | 29-Jun-2015
Why Data driven Testing :
If we have to write test cases for different domain ,controller and services, it is fine to go with interaction based testing(which contains descriptive name of test cases).
Problem :
But problem with this it, if we have to write test case for a action or service method which takes different values and outputs different result every time based on the input given to it. Then we have to replicate the code for each input series, which seems too much handy and replicated code also spoils the look of test cases like :
class CalculationServiceSpec extends Specification {
def "sum of two numbers"() {
expect:
// same line is repeated 3 times for variable input fields
service.calculateSum(1, 3) == 4
service.calculateSum(7, 4) == 12 //fails
service.calculateSum(0, 0) == 0
}
}
Solution :
Spock framework data driven testing supports testing of same code multiple times with varying inputs and outputs with the help of data variables and data tables. Using the data driven testing above code can be refcatored like this :
class CalculationServiceSpec extends Specification {
def "sum of two numbers"() {
expect:
service.calculateSum(value1, value2) == sum
where :
value1 | value 2 | sum
1 | 3 | 4
7 | 4 | 12 //fails
0 | 0 | 0
}
}
In the above code where clause contains a datatable in which first row is table header which is used to declare the data variables(in this case value1, value2 and sum). Below the table header,there are table rows which contain corresponding value for each data variables.
For each table row, test case logic is iterated once. If an iteration fails, the remaining iterations will never be executed.
I am here testing validation on a domain in single test case using data driven syntax :
Domain :
class User {
String username
String password
static constraints = {
username (nullable: false,blank: false,email: true, maxSize:60)
description (blank: false, minSize: 10, maxSize:600)
}
}
Test case :
class UserSpec extends Specification {
def setup :{}
def cleanup() {}
@Unroll
def "test validation on #field for the error : #error"(){
given :
mockForConstraintsTests User
User user = new User(username : '[email protected]',description: 'test description').save(flush :true)
when :
User testUser = new User()
user."${field}" = value
then :
!testUser.validate()
testUser.hasErrors()
testUser.errors['$field'] == error //mockForConstraintsTests gives the name of failed constraint
where:
error| value | field
'nullable'| null | 'username'
'blank'| '' | 'username'
'maxSize' | 'L'*61+'@gmail.com' | 'username'
'email'| 'test' | 'username'
null | '[email protected]' | 'username'
'nullable' | null | 'description'
'blank' | '' | 'description'
'minSize' | 't'*8 | 'description'
'maxSize' | 't'*601 | 'description'
}
}
Use of @Unroll :
As you see in above test case variable '#field' and '#error' are used and @Unroll is used in top of test case.If it is not done so, then the output will be like this :
test validation on #field for the error : #error with no iteration
@Unroll annotation makes the test case name more descriptive and understandable using the value of field like :
test validation on username for the error : nullable
test validation on username for the error : blank
It also makes the identification of iteration failure very easy.
Thanks
Shiv Kumar
Cookies are important to the proper functioning of a site. To improve your experience, we use cookies to remember log-in details and provide secure log-in, collect statistics to optimize site functionality, and deliver content tailored to your interests. Click Agree and Proceed to accept cookies and go directly to the site or click on View Cookie Settings to see detailed descriptions of the types of cookies and choose whether to accept certain cookies while on the site.
About Author
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.