I've written simple test in Groovy using Spock framework
class SimpleSpec extends Specification {
def "should add two numbers"() {
given:
final def a = 3
final b = 4
when:
def c = a + b
then:
c == 7
}
}
Variable a is declared using def and final keywords combination. Variable b is declared using only final keyword.
My question is: what's the difference (if any) between these two declarations? Should one approach be preffed to the other? If so, why?
User daggett ist right, final does not make a local variable final in Groovy. The keyword only has influence on class members. Here is a little illustration:
package de.scrum_master.stackoverflow
import spock.lang.Specification
class MyTest extends Specification {
def "Final local variables can be changed"() {
when:
final def a = 3
final b = 4
final int c = 5
then:
a + b + c == 12
when:
a = b = c = 11
then:
a + b + c == 33
}
final def d = 3
static final e = 4
final int f = 5
def "Class or instance members really are final"() {
expect:
d + e + f == 12
when:
// Compile errors:
// cannot modify final field 'f' outside of constructor.
// cannot modify static final field 'e' outside of static initialization block.
// cannot modify final field 'd' outside of constructor.
d = e = f = 11
then:
d + e + g == 33
}
}
When I switched one of my Spock projects to version 1.3 with Groovy 2.5 and noticed that this test no longer compiles now due to the compiler detecting the reassignment to final local variables. I.e. the inconsistency in Groovy <= 2.4 seems to be fixed.
final variables declared inside the methods are processed as usual variables in groovy
check the class below and the one generated by groovy (2.4.11)
ps: possible the given: section in spock generates code differently...
Related
I have below sample classes in my application:
class A {
Integer a
String b
Integer c = (a < 5) ? a+5 : a+10
}
class B {
void method1() {
A a = new A(a:4, b:"test")
log.print("c: ", a.c)
}
}
When my code is calling method1, then it outputs c = 14. but ideally it should 9.
How we can solve this without explicitly setting value for c?
Thanks in advance!
Not 100% sure of the question, and the example won't print anything as it will fail to add 5 to null, but an alternative might be to use the #Lazy annotation to defer creation of the value until such time as it is requested, ie:
class A {
Integer a
String b
#Lazy Integer c = { (a < 5) ? a+5 : a+10 }()
}
After it has been requested, it will keep this value, no matter how you change a and b (unless you change c yourself). From the question, I have no idea if this is what you want or not
class A {
Integer a
String b
def getC(){ (a < 5) ? a+5 : a+10 }
}
class B {
def method1() {
A a = new A(a:4, b:"test")
println("c: " + a.c)
}
}
new B().method1()
I am trying to retrieve the common items across two lists using Groovy. The following code works just fine, i.e the output from running this code is "DEBUG found in common Items : same". So far so good!
def list1 = ["same", "different"]
def list2 = ["same", "not the same"]
def commonItems = list1.intersect(list2)
for(int i=0; i < commonItems.size(); i++)
{
log.info("DEBUG found in common Items : " + commonItems[i])
}
I hit an issue when I try to apply the above principle to a list of objects - my issue is that the 'commonItems' list does NOT contain the single object I would expect, but is empty. Please note, my custom object 'ErrorWarningDetail' does override compareTo. Can someone see what I am doing wrong / make any suggestions? Thanks in advance!
First of all here is my custom class - note 'CompateTo' just checks the 'Code' field for now.
class ErrorWarningDetail implements Comparable
{
public String Code
public String Description
public String ErrorType
public String State
#Override
int compareTo(Object o) {
int result = Code <=> o.Code
result
}
}
Now here is the code that does the business. I would expect one object to be in 'commonItems' but it is infact empty - what am i doing wrong here? The output of running this is "DEBUG no common items"
def similarONE = new ErrorWarningDetail()
similarONE.Code = "100-1"
def similarTWO =new ErrorWarningDetail()
similarTWO.Code = "100-1"
def completelyDifferent = new ErrorWarningDetail()
completelyDifferent.Code = "697-2"
def List1 = []
def List2 = []
List1.add(similarONE)
List1.add(completelyDifferent)
List2.add(similarTwo)
def commonItems = list1.intersect(list2)
if (commonItems.size() == 0)
{
log.info("DEBUG no common items")
}
Implementing compareTo() is not enough in Java, you should be implementing equals/hashCode instead.
In Groovy there's a handy annotation for that. So, the script down below executes successfully:
import groovy.transform.EqualsAndHashCode
#EqualsAndHashCode( includes = [ 'code' ] )
class ErrorWarningDetail implements Comparable {
String code
String description
String errorType
String state
#Override
int compareTo(Object o) {
code <=> ( o?.code ?: '' )
}
}
def similarONE = new ErrorWarningDetail( code:"100-1" )
def similarTWO = new ErrorWarningDetail( code:"100-1" )
def completelyDifferent = new ErrorWarningDetail( code:"697-2" )
def list1 = [similarONE, completelyDifferent]
def list2 = [similarTWO]
def commonItems = list1.intersect list2
assert 1 == commonItems.size()
P.S. Please, DO NOT name fields starting with Capital letters!
The equals and hashCode are the methods utilized to determine object equality, so the intersect method would rely on those.
The compareTo method is utilized for sorting purposes.
Groovy has some convenient utilities for common tasks in the package groovy.transform
Below is the modified class with the annotations that makes it work as intended.
#EqualsAndHashCode(includes=["Code"])
#ToString(includeFields=true)
class ErrorWarningDetail implements Comparable
{
String Code
String Description
String ErrorType
String State
#Override
int compareTo(Object o) {
Code <=> o?.Code
}
}
I would like to increment the values based on assert results :
def a = 1
def b = 1
def c = 0
def d = 0
(assert a==b, "Mismatch") ? (c++) : (d++)
Is it possible?
You misunderstood one important part - assert is not a function and it does not return any value. It is a Groovy's (and Java) keyword (statement) that throws an exception if the expression on the right side evaluates to false, but it does not return any result. However, you can achieve expected result using ternary operator in the way it was designed to use:
def a = 1
def b = 1
def c = 0
def d = 0
a == b ? (c++) : (d++)
println "c = ${c}, d = ${d}"
Output:
c = 1, d = 0
You can read more about using assertions in Groovy's official "Testing Guide, chapter 2.1 Power Assertions".
If you really want to "ignore" the assert and continue, you can catch the exception it throws. E.g.
def a = 1
def b = 1
def c = 0
def d = 0
try {
assert a==b, 'Mismatch'
c++
}
catch (AssertionError e) {
d++
}
println([a,b,c,d])
I'd only use tactics like that, if some foreign code dictates that on me. This is very convoluted code unless you want to abuse the power-assert to generate a nice "warning" log message for you.
I have a situation where I have to write a code for a groovy script which is not written inside a class . Its just a plain groovy script. For some reason I can't show the actual code .But it would simply like this:
def var = 10
return var
You can create an object of the class and call run() method on it. This will instantiate the class and run the method in it.
You do not have to write tests specially in the case that you mentioned.
Use in-built assert for the same.
def var = 10
var++
assert 11 == var, 'Value mismatch for var'
One style is to write micro-tests inline, using the assert feature (as mentioned elsewhere):
def reverseString = { s ->
s?.reverse()
}
// test_reverseString
assert 'cba' == reverseString('abc')
assert '' == reverseString('')
assert null == reverseString(null)
def sumList = { list ->
(list == null) ? 0 :
(list.isEmpty()) ? 0 :
list.sum()
}
// test_sumList
assert 6 == sumList([1,2,3])
assert 0 == sumList([])
assert 0 == sumList(null)
// ---- main
println reverseString('esrever')
println sumList([1,2,3,4])
It is relatively easy to modify this code so that only the tests execute (e.g. based on a command-line argument).
I need to store a value in a variable in one method and then I need to use that value from that variable in another method or closure. How can I share this value?
In a Groovy script the scoping can be different than expected. That is because a Groovy script in itself is a class with a method that will run the code, but that is all done runtime. We can define a variable to be scoped to the script by either omitting the type definition or in Groovy 1.8 we can add the #Field annotation.
import groovy.transform.Field
var1 = 'var1'
#Field String var2 = 'var2'
def var3 = 'var3'
void printVars() {
println var1
println var2
println var3 // This won't work, because not in script scope.
}
def i_am_not_global = 100 // This will not be accessible inside the function
i_am_global = 200 // this is global and will be even available inside the
def func()
{
log.info "My value is 200. Here you see " + i_am_global
i_am_global = 400
//log.info "if you uncomment me you will get error. Since i_am_not_global cant be printed here " + i_am_not_global
}
def func2()
{
log.info "My value was changed inside func to 400 . Here it is = " + i_am_global
}
func()
func2()
here i_am_global variable is a global variable used by func and then again available to func2
if you declare variable with def it will be local, if you don't use def its global
class Globals {
static String ouch = "I'm global.."
}
println Globals.ouch
Like all OO languages, Groovy has no concept of "global" by itself (unlike, say, BASIC, Python or Perl).
If you have several methods that need to share the same variable, use a field:
class Foo {
def a;
def foo() {
a = 1;
}
def bar() {
print a;
}
}
Just declare the variable at class or script scope, then access it from inside your methods or closures. Without an example, it's hard to be more specific for your particular problem though.
However, global variables are generally considered bad form.
Why not return the variable from one function, then pass it into the next?
I think you are talking about class level variables.
As mentioned above using global variable/class level variables are not a good practice.
If you really want to use it. and if you are sure that there will not be impact...
Declare any variable out side the method. at the class level with out the variable type
eg:
{
method()
{
a=10
print(a)
}
// def a or int a wont work
a=0
}
def sum = 0
// This method stores a value in a global variable.
def add =
{
input1 , input2 ->
sum = input1 + input2;
}
// This method uses stored value.
def multiplySum =
{
input1 ->
return sum*input1;
}
add(1,2);
multiplySum(10);
Could not figure out what you want, but you need something like this ? :
def a = { b -> b = 1 }
bValue = a()
println b // prints 1
Now bValue contains the value of b which is a variable in the closure a. Now you can do anything with bValue Let me know if i have misunderstood your question