Setting member variables by name in Spock - groovy

I am writing a Spock integration test for a function that takes a DTO, that has a lot of member variables. The functionality to test is that one user role is allowed to change some member variables, but if that user tries to change one of the other fields, it should fail.
I don't want to manually write a test for every single field, so I figured, I could be using a where: table like so:
where:
fieldname | value | isAccepted
"fieldA" | "val" | true
"fieldB" | "val" | false
...
For that, I'd have to be able to set the fields by the name in a string. In Java I'd have to use reflection for that. In Python I could just use setattr(object, fieldname, value) for that.
Since I writing the test in Groovy, is there something idiomatic for that?

Yes there is an idiomatic way to dynamically access fields an methods in groovy. You just use a GString to reference the field.
class A {
String foo = 200
String bar = 400
}
def a = new A()
def field = "foo"
println a."$field"
field = "bar"
println a."$field"
a."$field" = 600
println a.bar
Outputs
200
400
600
Test it in the Groovy Web Console

Related

Parameterizing Objects in spock

I have a problem with parameterizations of list of object by using spock where block. It seems the ListInput value is not taking from the where clause and always coming null value. I have verified the same feature for string and other primitive types and it is working fine.
Does Spock support parameterizations objects ? If yes what is the issue here .
def "check Param Of List of Objects"()
{
expect:
def a= hasflag(ListInput);
a== flag
where:
ListInput | flag
BOList1 | true
BOList2 | false
}
Here the type of BOList1 is an java ArrayList contains the object
You haven't really provided enough information for a definitive answer but I'll try to help.
The where block isn't exactly just a block of code, it's more like a number of parameters passed to a method. It can do a lot, but sometimes you need to pass your code a little differently.
Of note:
- Void methods aren't allowed (but you can get around this using .with{} )
- An iterative parameter cannot also be a derived parameter (constructed from other parameters)
- If you're referencing class level variables (defined within the class but outside this test) they need to be given the #Shared annotation for your tests to have access.
Given more information about where your lists are coming from will help me give better advice.
Final tip; explicitly typecast your parameters to see if that gives you anymore information
def "check Param Of List of Objects"(ArrayList listInput, boolean flag) {
expect:
flag == hasflag(ListInput);
where:
listInput | flag
BOList1 | true
BOList2 | false
}

Groovy DSL getting anonymous String assignments

I have a DSL that looks like this:
aMethod {
"a name"
"another name"
"and a third name"
}
My Problem is that I'm unable to access the three string, because calling the closure only returns the last statement. I tried to override the constructor of String(char[] value) which is called when an anonymous String-statement occurs:
def original
// primitive way to get the String(char[])-constructor
String.class.constructors.each {
if(it.toString() == "public java.lang.String(char[])") {
original = it
}
}
// overriding the constructor
String.metaClass.constructor = { char[] value ->
def instance = original.newInstance(value)
// ... do some further stuff with the instance ...
println "Created ${instance}"
instance
}
// teststring to call String(char[] value)
"teststring"
Unfortunately it didn't work and I thought anyway that it is quite complicated.
Thank you for the comments. Actually it would be great to define everything without quotes. But: After having a dsl that can be translated to java objects I'd loved to have additional annotations in my language at development time. I want to annotate duplicate names and so on. The IDE's I know better, Intellij and Eclipse handle Strings "a name" as one PSI-Elements. Splitting these elements can be very inconvinient ... I guess. I think statements in a closure like aMethod {a name} would result in an interpretation like aMethod {a.name}. That would mean that instead of having a StringLiteral Psi "a name", I would have an Object-Psi and a MethodCall-Psi or something like that. I don't know, and my next goal is just "parsing/creating" my java objects. Are you sure that it is impossible to override the String-Constructor?
Is any constructor called when you have a groovy script with this content:
"hello World"

Use groovy categories to add dynamic properties

Expanding on this blog post, I am trying to use a category to create a simple DSL for use with the javax.measure (JSR-275) classes (similar to TimeCategory for time intervals)
However, I do not want to add boilerplate code for each of the possible available methods (getMeter, getMilliMeter, getKelvin, getSecond etc.). I thought overriding the getProperty(String) method would work, but alas, it looks like the getProperty method defined in the category is not used when accessing the property directly.
Here is some simplified code to demonstrate:
import javax.measure.quantity.Length;
import javax.measure.unit.Unit;
import javax.measure.Measure;
#Category(Number)
class LengthCategory {
public Measure<BigDecimal, Length> getProperty(String unit){
return Measure.valueOf(this,Unit.valueOf(unit));
}
}
use(LengthCategory){
println 3.getProperty("m") // this works
println 3.m // this reports a non-exisiting property
prinlln 3.'m' // as does this
}
Assuming other methods of dynamically adding properties to a runtime object (e.g. Expando, subclassing GroovyInterceptible, mixins and other metaclass manipulations) is not viable and I would really rather not have to manually code getters for every possible unit and SI prefix combination. There are obviously other ways to go about creating a DSL for measurements, but I would still like to understand why this method would not work.
Could someone explain why the getProperty method of the category does not override .propertyName usage? I am obviously missing something important about the resolution of property names using the metaclass during runtime.
I don't know why getProperty doesn't work on categories. But you can define a get method on them that does basically the same (i think). This works:
#Category(Number)
class LengthCategory {
def get(String unit) {
"$this $unit"
}
}
use (LengthCategory) {
println 3.m // 3 m
println 3.'m' // 3 m
}
As far as I can tell, you can't actually extend Integers with full (i.e., readable and writable) properties using Category -- only with methods.
You can extend an Integer using read-only properties by using the method version of the property. You can even make it writable by including a set method. However, there doesn't seem to be a way to store the value passed in other than in a static variable and that ends up affecting all Integers.
Example:
$ cat catprop
#!/usr/local/bin/groovy
#Category(Integer)
class CatInteger {
private static String str = "default"
public static String setN(Integer i, String _str) { str = _str }
public static String getN(Integer i) { return str }
}
use (CatInteger) {
3.n = "333a"
println "3.n is " + 3.n
3.n = "333b"
println "3.n is " + 3.n
4.n = "444"
println "4.n is " + 4.n
println "3.n is " + 3.n
}
$ catprop
3.n is 333a
3.n is 333b
4.n is 444
3.n is 444
$
Note that in the last line 3.n return "444" because the stored field is static. I suppose that one could use a private HashMap and store a value for every Integer accessed, but that's too ugly to contemplate.
Another possibility would be to use the MetaClass Interface's getProperty() and setProperty(). However, I haven't looked into that so I don't know if it would work or not (just a thought).
Nice answer, but not sure, if you's still want to use JSR-275 now that JSR-363 is final?;-)

GORM - Update object without retrieving it first

I'd like to be able to update a previously persisted object for which I have an id without having to retrieve it first. The main thing that I'm trying to avoid is having to copy multiple values into the object's fields when that object has been retrieved from the database. I have these values in a map with keys corresponding to the field names so it's trivial to create the object via a constructor with the map as an argument. Unfortunately, an object created this way results in a new database record when saved even though the id field is set to that of an existing record.
I'm currently using a slight variation on one of the examples shown here for copying Groovy class properties but it's not a very elegant solution for multiple reasons.
Basically I'd like to be able to do something like this:
class Foo {
int a
String b
}
def data = [id: 99, a: 11, b: "bar"] //99 is the id of an existing record
def foo = new Foo(data)
foo.update() //or some other comparable persistence mechanism
Thanks
As long as your map keys have the same name as your object properties, you can use executeUpdate without specifying the individual property names with a closure or function like the following:
def updateString = { obj, map ->
def str = ""
map.each { key, value ->
str += "${obj}.${key}=:${key},"
}
return str[0..-2]
}
def data= [foo:"bar", machoMan:"RandySavage"]
In this case, println updateString("f", data) returns "f.foo=:foo,f.machoMan=:machoMan".
Then you can do this:
Foo.executeUpdate("update Foo f set ${updateString("f", data)}", data)
Or of course you could combine that all together into one closure or function.
You can use the executeUpdate method on the GORM domain class:
Foo.executeUpdate("update Foo f set f.a=:a, f.b=:b where f.id=:id", data)

How to get groovy to evaluate ${sth} when stored in string?

I'm getting a text which contains ${somethingElse} inside, but it's just a normal String.
I've got a class:
class Whatever {
def somethingElse = 5
void action(String sth) {
def test = []
test.testing = sth
assert test.testing == 5
}
}
Is it possible with groovy?
EDIT:
my scenario is: load xml file, which contains nodes with values pointing to some other values in my application. So let's say I've got shell.setVariable("current", myClass). And now, in my xml I want to be able to put ${current.someField} as a value.
The trouble is, that the value from xml is a string and I can't evaluate it easily.
I can't predict how these "values" will be created by user, I just give them ability to use few classes.
I cannot convert it when the xml file is loaded, it has to be "on demand", since I use it in specific cases and I want them to be able to use values at that moment in time, and not when xml file is loaded.
Any tips?
One thing you could do is:
class Whatever {
def somethingElse = 5
void action( String sth ) {
def result = new groovy.text.GStringTemplateEngine().with {
createTemplate( sth ).make( this.properties ).toString()
}
assert result == "Number 5"
}
}
// Pass it a String
new Whatever().action( 'Number ${somethingElse}' )
At first, what we did, was used this format in xml:
normalText#codeToExecuteOrEvaluate#normalText
and used replace closure to regexp and groovyShell.evaluate() the code.
Insane. It took a lot of time and a lot of memory.
In the end we changed the format to the original one and crated scripts for each string we wanted to be able to evaluate:
Script script = shell.parse("\""+stringToParse+"\"")
where
stringToParse = "Hello world # ${System.currentTimeMillis()}!!"
Then we were able to call script.run() as many times as we wanted and everything performed well.
It actually still does.

Resources