Spock - setup spec with groovy trait and #BeforeClass - groovy

I was trying to setup a common array of objects which are loaded and deserialised from json file in resources and tried to do this by using groovy trait with setup() method.
Trait:
Object[] arr
#BeforeClass
def setupTrait() {
arr = loadFromFile("xxx.json")
}
Test:
def setup() {}
def "test"() {
arr.size() //here arr is null, although the setup in groovy is called
}
Working solution.
Trait:
static Object[] arr = loadFromFile("xxx.json")
Test:
def setup() {}
def "test"() {
arr.size() //here arr is ok.
}
The question is why the first isn't working right?
If I use #Before annotation and arr is loaded before each test, it's somehow working...

There are some minor mistakes that I suggest to rewrite in a more "spock"-y way:
in spock you're supposed to use def setupSpec() fixture method and not #BeforeClass
if you want to initialize a variable in setupSpec that indeed will run only once for all test cases you are supposed to put #Shared annotation on the field.
But then, even if the code will look like this:
trait SampleTrait {
#Shared List arr
def setupSpec() {
arr = [1,2,3]
}
}
It still doesn't work. Now, It looks like you've encountered an open issue in spock:
https://github.com/spockframework/spock/issues/83
The issue is open, but the workaround exists and is suggested in the discussion: put a word static (you have actually done that :)). The reason: #Shared annotation cannot be processed by Spock when they appear in traits.
So, all-in-all I believe the best you can get is:
trait SampleTrait {
static List arr
def setupSpec() {
arr = [1,2,3]
}
}
class SampleTestSpec extends Specification implements SampleTrait {
def "list equality"() {
expect:
arr == [1,2,3]
}
}

Related

Groovy CliBuilder: any method defined?

I'm very new to Groovy.
Very simple question about the code found in CliBuilder.
http://docs.groovy-lang.org/latest/html/gapi/index.html?overview-summary.html
def cli = new CliBuilder(name:'ls')
cli.a('display all files')
cli.l('use a long listing format')
cli.t('sort by modification time')
def options = cli.parse(args)
assert options // would be null (false) on failure
assert options.arguments() == ['*.groovy']
assert options.a && options.l && options.t
The CliBuilder class behaves as knowing whatever methods we want to call in advance. By what Groovy's feature it can be supported?
This is called Runtime metaprogramming.
If you want to create your own class with "dynamic methods", the easiest way is to implement the GroovyInterceptable interface and add the invokeMethod method to your class.
class Interception implements GroovyInterceptable {
def definedMethod() { }
def invokeMethod(String name, Object args) {
'invokedMethod'
}
}
Whenever a method is called on an instance if the class Interception, invokeMethod is called instead. Note that this is also true for methods actually defined in the class (e.g. definedMethod)
You can use the metaClass to call the actual method like this
class Interception implements GroovyInterceptable {
def definedMethod() { }
def invokeMethod(String name, Object args) {
if (name == "actualMethod") {
return metaClass.invokeMethod(this, name, args)
}
return "invokedMethod: $name($args)"
}
def actualMethod() {
return 'hello there'
}
}
Here a call to actualMethod still goes through invokeMethod, however invokeMethod contains logic to call the actual method.
There are some other ways (see link on top) to acomplish similar behavior, but I found this to be the easiest.
Note that runtime metaprogramming is incompatible with #CompileStatic unless you add a TypeCheckingExtension to mitigate this.
Run Example

Create a new class "on the fly"?

... specifically in Groovy (hence tag)?
In Java you can't do this... but in dynamic languages (e.g. Python) you typically can.
An attempt to do something like in the given block of a Spock feature (i.e. test method) meets with, in Eclipse:
Groovy:Class definition not expected here. Please define the class at
an appropriate place or perhaps try using a block/Closure instead.
... an "appropriate" place would obviously be outside the feature. This would be clunky and not groovy. Having used Groovy for a few months now I get a feel for when Groovy should offer something groovier.
So say I'd like to extend my abstract class AbstractFoo and make a new subclass Foo, in my feature, is there any way to "use a block/Closure" to achieve something like that?
You can simply create an anonymous class by instantiating AbstractFoo and providing inline implementation of abstract methods. Consider following example:
abstract class AbstractFoo {
void bar() {
println text()
}
abstract String text()
}
def foo1 = new AbstractFoo() {
#Override
String text() {
return "Hello, world!"
}
}
def foo2 = new AbstractFoo() {
#Override
String text() {
return "Lorem ipsum dolor sit amet"
}
}
foo1.bar()
foo2.bar()
Both foo1 and foo2 implement AbstractFoo and they provide different implementation of text() method that results in different bar() method behavior. Running this Groovy script produces following output to the console:
Hello, world!
Lorem ipsum dolor sit amet
It's nothing Groovy-specific, you can achieve exactly the same behavior with Java. However you can make it a little bit more "groovier" by casting a closure to a AbstractFoo class, something like this:
def foo3 = { "test 123" } as AbstractFoo
foo3.bar()
In this case closure that returns "test 123" provides an implementation for an abstract text() method. It works like that if your abstract class has only single abstract method.
Abstract class with multiple abstract methods
But what happens if an abstract class has multiple abstract methods we want to implement on fly? In this case we can provide implementation of this methods as a map, where keys are names of abstract methods and values are closures providing implementation. Let's take a look at following example:
abstract class AbstractFoo {
abstract String text()
abstract int number()
void bar() {
println "text: ${text()}, number: ${number()}"
}
}
def foo = [
text: { "test 1" },
number: { 23 }
] as AbstractFoo
foo.bar()
This example uses an abstract class with two abstract methods. We can instantiate this class by casting a map of type Map<String, Closure<?>> to AbstractFoo class. Running this example produces following output to the console:
text: test 1, number: 23
Creating non-anonymous classes on fly in Groovy
Groovy also allows you to create a class e.g. from a multiline string using GroovyClassLoader.parseClass(input) method. Let's take a look at following example:
abstract class AbstractFoo {
void bar() {
println text()
}
abstract String text()
}
def newClassDefinitionAsString = '''
class Foo extends AbstractFoo {
String text() {
return "test"
}
}
'''
def clazz = new GroovyClassLoader(getClass().getClassLoader()).parseClass(newClassDefinitionAsString)
def foo = ((AbstractFoo) clazz.newInstance())
foo.bar()
Here we are defining a non-anonymous class called Foo that extends AbstractFoo and provides a definition of test() method. This approach is pretty error prone, because you define a new class as String, so forget about any IDE support in catching errors and warnings.
Providing a subclass in a test specification
Your initial question mentioned about an attempt to create a class for a specification in a given: Spock block. I would strongly suggest using the simplest available tool - creating a nested private static class so you can easily access it inside your test and you don't expose it outside the test. Something like this:
class MySpec extends Specification {
def "should do something"() {
given:
Class<?> clazz = Foo.class
when:
//....
then:
///....
}
private static class Foo extends AbstractFoo {
}
}

Method aliasing in class with Groovy

I'm going to internationalize groovy API abit.
For final class (e.g. String)
String.metaClass.вСтроку = {-> this.toString() }
However, this will create additional closure. Isn't there any way to just alias method with another method?
Something like this:
String.metaClass.вСтроку = String.metaClass.&toString
You could use #Category transform like this
#Category(String) class StringInternationalization {
String вСтроку() {
this.toString()
}
int длина() {
this.length()
}
}
class ApplyMixin {
static {
String.mixin(StringInternationalization)
final helloString = "Привет мир!"
println helloString.вСтроку()
assert helloString.длина() == helloString.length()
}
}
new Main()
This will create 1 Category class for each localised class and one class to apply all mixin transformations(to register all methods.) Also should be faster, then individual closures.
More reading here: http://groovy.codehaus.org/Category+and+Mixin+transformations

ExpandoMetaClass - Static Methods + singleton + overloaded functions

Using ExpandoMetaClass Static Methods can be added dynamically, how can i use this ExpandoMetaClass in Singleton object, with overloaded static function in it, let say the sample program need to be re written using ExpandoMetaClass whats needs to changed in the below program
#Singleton
class testA {
def static zMap = [:]
static def X() {
Y()
}
static def Y() {
}
static def X(def var) {
Y(var)
}
static def Y(def var) {
zMap.put(var)
}
}
One of the reasons to use a singleton is to avoid having static state and methods in a class. If you're using #Singleton, there's no reason to have static methods or fields. The way to use a singleton is like this:
#Singleton class TestA {
def someField = "hello"
def methodX() {
someField
}
}
println TestA.instance.methodX()
You can extend the singleton using ExpandoMetaClass like so:
TestA.instance.metaClass.newMethod = { -> "foo" }
TestA.instance.metaClass.methodX = { -> "goodbye" }
println TestA.instance.newMethod()
println TestA.instance.methodX()
If you really want a static method, you can do something like this:
TestA.metaClass.static.methodY = { -> "I am static" }
println TestA.methodY()
Note that if you override the class metaClass, rather than the instance metaClass, it won't apply to the instance if the instance has already been created. To get around this use #Singleton(lazy = true) and override the metaClass before accessing the instance.

Groovy Prototype Object

I have a method with an incoming variable, which represents a script.
e.g.
hello.groovy
Foo.init(this)
Foo.groovy
class Foo {
static init(app) {
}
}
What is the best way to add a ton of new functionality to the app variable in the init method? Basically, I would like to add all the functionality of another object to the app object.
For instance, if I had another class:
class Bar {
def a() { }
def b() {
}
}
I would like the app object to basically be a new Bar(). In JavaScript, this is easy by using the prototype object, but I cannot seem to get it working in groovy. What is the best way to accomplish this? Or should I be doing something differently?
YourClass.metaClass.static.yourMethod is the most similar to JS prototype I've seen in Groovy. Check this link out:
Groovy meta-programming - adding static methods to Object.metaClass
Cheers.
There are several ways to do this and each has advantages and disadvantages. On the Groovy Documentation page, the section on Dynamic Groovy illustrates several of these. If I understand you correctly, the simplest way is to just use the metaClass of an instance to add new functionality, a la:
class Foo {
static void init (a) {
a.metaClass.a = { println "a()"; }
a.metaClass.b = { println "b()"; }
}
}
def myObject = new Object();
Foo.init (myObject);
myObject.a();
myObject.b();
The easiest way to do this would be with a mixin. Basically you can call mixin on app's class and pass it another class to incorporate that functionality into it.
I've modified your example to show this mixing in the Bar class.
class Foo {
static init(app) {
app.class.mixin Bar
}
}
class Bar {
def a() { println "a called" }
def b() {
println "b called"
}
}
def app = new Object()
Foo.init(app)
app.a()
app.b()
The output of this would be:
a called
b called
In this case I added Bar to the Object class but you could add it to any class in your application.

Resources