Creating spock tests in runtime - groovy

Is there any possibility to create spock tests in runtime? I tried to create several meta-methods in a loop within a GebSpec but they are ignored during the tests execution.
Or maybe somebody could suggest any workarounds?
Thanks in advance!

As #Tim mentioned, datatables are the way to go.
You don't need to duplicate code in data tables, you can make them fully dynamic.
#Unroll
def "Check form submit params: '#login', '#pwd'. Expected - #result"(String login, String pwd, boolean result) {
setup:
// do your test
where: [login, pwd, result] << [ [ "user", "qwerty", true], [ "user", "1234", false] ]
}
Please note nested arrays in where clause. It can actually be a fully dynamic array created at runtime.
Also please notice an #Unroll annotation, as it will give you nice test method names.

you can simple write loop/sql query in where clause. a test suite runs accordingly to the number of where possible.
example:
#Unroll
def "test suite for each student"(){
given: ""
.......................
and : ""
.......................
then: ""
........................
where: ""
for (StudentList student : list){
//operations
//load the values in the variables such as there numbers or ids
}
}
if the loop is true for 10 students, the suite will be executed 10 times

Related

How to get the key from a nested map (JSON) using given value in Groovy in JIRA Scriptrunner

Hope this question finds you all in good health.
As per title, would like to know how this is done in Groovy. Found a few, such as this, but the question and answer did not help.
The JSON is like this
def ​json = '''{
"boston": [
{
"name":"bob",
"phone":"242 123123",
},
{
"name":"alice",
"phone":"212-123-345",
}
],
"chicago": [
{
"name":"charlie",
"phone":"313-232-545",
},
{
"name":"denise",
"phone":"414-123-546",
}
]
}'''
But how do I use the value, for example bob to get boston?
When you use parsedjson['chicago']['email'], the result would be
[charlie#chicago.com, denise#chicago.com]
I tried to do something like
def getKey = parsedjson['email']?.key
as suggested here but in JIRA ScriptRunner console returned null
Any pointer is greatly appreciated in advance!
parsedjson['email']?.key returned null because key is not a List method. key is an Entry method so to find the key from a value you have to iterate through the Map's Entry Set.
Here's an example to get the city from the person's name using Map.find which returns an Entry:
parsedjson.find { it.value.find { it["name"] == "bob" } }.key

Groovy script assertion that validates the presence of some values in a JSON response

So I'm using an testing tool called ReadyAPI and for scripting it uses the Groovy language. I'm not familiar with the language and the fact that it's based on Java it somehow makes it even worse.
Now I'm trying to validate a REST response in JSON with an assertion that checks that certain elements exist in the response.
This is the code that I have now:
import groovy.json.*
def response = context.expand( 'RequestResponseHere' )
def object = new JsonSlurper().parseText(response)
assert response.contains("CODE1")
assert response.contains("CODE2")
assert response.contains("CODE3")
assert response.contains("CODE4")
The assertion seems to work but I was wondering if there is maybe a simpler way to do it than to have to write so many lines and making it less 'bulky'?
Any help is greatly appreciated.
Thank you!
Added an example of the json data that I have to parse:
What I need is to check that the value of "code" is always part of a list of acceptable values e.i. CODE1, CODE2, etc.
{
"_embedded": {
"taskList": [
{
"code": "CODE1",
"key": 123
},
{
"code": "CODE2",
"key": "234"
},
{
"code": "CODE3",
"key": "2323"
},
{
"code": "CODE4",
"key": "7829"
},
{
"code": "CODE5",
"key": "8992"
}
]
}
}
If you want to check for certain things to be there, you can DRY that
code with:
["code1","code2"].each{ assert response.contains(it) }
And as stated in the comments, if you want to make sure, "all are there,
but I don't care for the order", extracting the values and comparing it
as results can shorten this:
assert response._embeded.taskList*.code.toSet() == ["code1", ...].toSet()
Note the use of *., which is the "spread operator". It is basically
the same as ...collect{ it.code }. Then comparing the string sets
does the rest (this is fine if you are comparing not to many items since
the power assert will print all the items along the failed assertion; if
you have to find the proverbial needle in the haystack, you are better
off writing something smarter to check the two sets).
The assertion seems to work but I was wondering if there is maybe a
simpler way to do it than to have to write so many lines and making it
less 'bulky'?
Unclear what it is that is bulky but if what you want is to lessen the number of statements, one thing you could do is use a single assert.
Instead of this:
assert response.contains("CODE1")
assert response.contains("CODE2")
assert response.contains("CODE3")
assert response.contains("CODE4")
You could have this:
assert response.contains("CODE1") &&
response.contains("CODE2") &&
response.contains("CODE3") &&
response.contains("CODE4") &&

How can I use Arrow-kt's Some() in Groovy code?

I'm trying to test my Kotlin code, which has Arrow-kt types, using Spock in Groovy. However, I'm not able to use Arrow-kt's additions such as Some. For example, I have a test as follows:
#Unroll
def "add returns #expected for queryRecord #queryRecord"() {
given:
def ip = "ip"
def rule = "rule"
when:
def result = unit.add(ip, rule)
then:
1 * dynamoDBMapperMock.load(ActionRecord.class, ip) >> queryRecord
result == expected
where:
queryRecord | expected
new ActionRecord() | None.INSTANCE
null | Some(new ActionInternal("ip"))
}
While the first data row succeeds with no problems, the second one fails with the following error:
groovy.lang.MissingMethodException: No signature of method: package.name.EventSpec.Some() is applicable for argument types: (package.name.ActionInternal) values: [ActionInternal(dropletIp=null)]
Possible solutions: Mock(), Spy(), Stub(), dump(), Mock(groovy.lang.Closure), Mock(java.lang.Class)
I've tried .some() as well, but not to avail. Apparently Groovy can't access Kotlin extensions, but Some is simply a data class[1], so I'm not sure why I cannot use it in Groovy.
Yes, you can use Arrow Datatypes in Groovy, the result is not as idiomatic as in Kotlin because the library heavily depends on extension functions and functions in the companion object
Example
import arrow.core.Option
import static arrow.core.OptionKt.getOrElse
static main(args){
println 'What is your name?'
def name = Option.#Companion.fromNullable(System.in.newReader().readLine())
.filterNot { it.isEmpty() }
.map { it.toUpperCase() }
println("Welcome ${getOrElse(name) { 'Anonymous' }}")
}
Output
'Welcome JOHN' (or 'Welcome Anonymous' if the provided name is null or empty)
As you can see, to be able to use getOrElse extension function, we need to import it as a static method
Hint
Do not use Some directly unless you are absolutely sure the value is not null, otherwise, you should rely on Option.fromNullable to safely lift the value to the Option context (i.e create Some or None depending if the value is null or not)

Excluding testcases from testsuite properties in Soapui

I want to disable certain test cases based on the value of some test suite properties (i.e if the property IsActive1 = false, then testcase1 will be disabled).
I used this code at test suite setup script but got an error:
def testSuite = context.testCase.testSuite;
def totalTestCases = testSuite.getTestCases().size();
for(n in (0..totalTestCases-1)) {
if(testSuite.getTestCaseAt(n).name == "${#TestSuite#IsActive}"){
testSuite.getTestCaseAt(n).setDisabled(true)
}
}
How can I do that?
Here is how I would go to achieve this.
Assuming that there is a suite with test cases, namely TestCase1, TestCase2, TestCase3, TestCase4, TestCase5. Using this approach, it would be a simple change of the property value to include or exclude the test case name to be disable. I believe that this would be better to change things from one place(single property) instead of changing IsActive property for each test case. If you have more cases to handle this would be a burden (going to each case and modify true or false for IsActive)
Create a custom property at test suite level, say DISABLE_TESTS with value (comma separated list to disable) as TestCase1, TestCase5
Here is the Setup Script at Suite level which would achieve to selectively execute the test cases.
/**
* Test Suite Setup Script
* Enable or disable selected list of test cases
* Based on the test suite property DISABLE_TESTS value
**/
//Disables a Test case
def disableTestCase(testCaze) {
log.info "Disabling test case : ${testCaze.name}"
testCaze.disabled = true
}
//Enables a Test case
def enableTestCase(testCaze) {
log.info "Enabling test case : ${testCaze.name}"
testCaze.disabled = false
}
//Read the test case names to enable and convert it to list
def disableList = testSuite.getPropertyValue('DISABLE_TESTS')?.split(',')?.collect { it.trim()} ?: []
log.info "List of test for disable: ${disableList}"
//Loop thru the test cases and enable or disable
testSuite.testCaseList.each { kase ->
//If the above list contains test case name disable, enable otherwise
if (disableList && disableList.contains(kase.name)) {
disableTestCase(kase)
} else {
enableTestCase(kase)
}
}
Since some of the cases are disabled, it would be good to enable all the cases as part of Test Suite Teardown Script. It would look mostly same, but there wont be any condition.
/**
* Test Suite Teardown Script
* Which enables all the test cases after selective execution
**/
//Enables a Test case
def enableTestCase(testCaze) {
log.info "Enabling test case : ${testCaze.name}"
testCaze.disabled = false
}
//Loop thru the test cases and enable
testSuite.testCaseList.each { kase ->
enableTestCase(kase)
}
You can do that with a Groovy script. You could place this script in the Setup script tab on testSuite Window, in order that the script is executed before your testSuite, disabling/enabling testCases depending on the properties.
Based on your requeriments this script could be something like:
// get property names getting only
// the one which start with "isactive"
def isActiveList = testSuite.getPropertyNames().findAll {
it.toLowerCase().startsWith('isactive')
}
log.info isActiveList
// get testCaseList in order
def testCaseList = testSuite.getTestCaseList()
// for each "isactive" property
// enable or disable the corresponding
// testCase
isActiveList.each{ name ->
// get the value
def isActive = testSuite.getPropertyValue(name).toBoolean()
// get the order from the property name
def testCaseIndex = name.toLowerCase() - 'isactive'
log.info "testCase at index $testCaseIndex will be disabled ${!isActive}"
// get the testCase and enable/disable depend
// on isactive property
// NOTE: IsActive1 corresponds to array pos 0
// so a -1 is necessary
log.info testCaseList[testCaseIndex.toInteger()-1]?.disabled = !isActive
}
Maybe it's better to rename your properties based on the testCase name's to enable/disable instead of using a number; to avoid undesired behaviors if you change i.e the testCase order or add a new one...
Hope it helps,

Cannot perform unit test with function which have createCriteria() statement

I want to write a unit test (by JUnit) to test value of this function in Groovy:
String getPeopleNamesById(int[] peopleIds) {
List<String> names = People.createCriteria().list{
projections { property("name") }
'in' ("id", peopleIds)
}
return names ? names.join(", ") : "";
}
But the unit test always fails when reading this statement: List names = People.createCriteria().list{...}
groovy.lang.MissingMethodException: No signature of method: People.createCriteria() is applicable for argument types: () values: [].
I guess it because of calling to functions which execute some DB connections and queries?
Could you please help me write this test? Thank you so much!
Criteria queries aren't available in unit tests, and aren't provided by mockDomain. You can either mock your criteria queries yourself, e.g. with mockFor, or make your test an integration test, where you have access to a full database environment.
Here's an example of how you could mock your query:
mockFor(People).demand.static.createCriteria = { ->
[list: { closure -> [ <some mock objects> ] } ]
}

Resources