cancel
Showing results for 
Search instead for 
Did you mean: 

Groovy untyped variables: Just Say No

tgeliot
Contributor

Groovy untyped variables: Just Say No

I got thoroughly bitten in the ass yesterday by using untyped variables in a Groovy script in ReadyAPI.  Consider, what’s wrong with the following code?

 

def iterationCount = 0;

def timeoutMinutes = context.expand( '${#TestCase#SW update timeout minutes}' )

log.info "timeoutMinutes : ${timeoutMinutes}"

 

while (complete == 0){

     log.info("iterationCount : $iterationCount, timeoutMinutes : $timeoutMinutes")

     if (iterationCount >= timeoutMinutes) {

           log.error("Update software timed out after $timeoutMinutes minutes")

           testRunner.fail ("Updating software took too long (> $timeoutMinutes minutes)");

           complete = 1

     } else {

           . . .

     }

     iterationCount++

}

 

 

Hint:  there’s nothing wrong with the call to context.expand or its parameter.

The first call to log.info logs

                timeoutMinutes : 1

The second call logs

                iterationCount : 0, timeoutMinutes : 1

                iterationCount : 1, timeoutMinutes : 1

                iterationCount : 2, timeoutMinutes : 1

                iterationCount : 3, timeoutMinutes : 1

                iterationCount : 4, timeoutMinutes : 1

                iterationCount : 5, timeoutMinutes : 1

etc.

 

WTF?

 

The answer is that iterationCount is implicitly made an integer, and because context.expand returns String, timeoutMinutes is implicitly made a String.

Then in the expression (iterationCount >= timeoutMinutes), timeoutMinutes is converted to an integer, but instead of doing the sane thing like Perl would, and converting the string “1” into the integer 1, Groovy converts “1” into the ASCII value of the character 1, which is 49.  So the loop can iterate 49 times before timing out.

 

The solution to this madness is to never use “def” to declare a variable.  Declare them as what they are:  “int” or “String” or “Boolean” or whatever.  Once I did that, Groovy threw an error at assigning the (String) result of context.expand into the int variable timeoutMinutes, and I knew that I needed to add a call to Integer.parseInt to convert the String result of context.expand into an integer value.

 

This only consumed half a day.  Don’t let it happen to you.

2 REPLIES 2
nmrao
Community Hero

Re: Groovy untyped variables: Just Say No

SoapUI properties are stored as String only. It is users responsibility to read it as required type.

In this case, you can simple use

def timeoutMinutes = context.expand( '${#TestCase#SW update timeout minutes}' ) as Integer


Regards,
Rao.
tgeliot
Contributor

Re: Groovy untyped variables: Just Say No

Indeed using "as Integer" is a tidier solution to converting the string to an integer, rather than calling Integer.parseInt or anything like that, thanks.

New Here?
Join us and watch the welcome video:
Announcements
Top Kudoed Authors