In our Integration Tests we wan't to compare every field of an Object returned by an Rest Controller with an object constructed in the test.
This example illustrates the problem:
class RestIntegrationTest extends Specification {
def "Should return contracts"() {
when:
def actual = callRestController()
then:
// compare all fields of actual with "contract"
actual == new Contract(
number: "123",
signDate: "2017-04-01",
address: new Address(
name: "Foobar",
street: "Foostreet",
city: "Frankfurt",
zip: "60486"
),
persons: [new Person(name: "Christian")]
)
}
def callRestController() {
return new Contract(
number: "123",
signDate: "2017-04-01",
address: new Address(
name: "Foobar",
street: "Wrong Street",
city: "Frankfurt",
zip: "60486"
),
persons: [new Person(name: "Frank")]
)
}
static class Contract {
String number
String signDate
Address address
Person[] persons
}
static class Address {
String name
String street
String city
String zip
}
static class Person {
String name
}
}
As output we like expect something like this:
address.street "Wrong Street" != "Foostreet"
persons[0].name "Christian" != "Frank"
Breaking the assert into multiple "==" lines would lead into the correct output, but that will be not handy since some objects are quite huge.
You can try the groovy's #EqualsAndHashCode:
import groovy.transform.EqualsAndHashCode
#EqualsAndHashCode
static class Address {
String name
String street
String city
String zip
}
You can use unitils assertReflectionEquals
http://unitils.sourceforge.net/tutorial-reflectionassert.html
It's not comprehensive but may be sufficient for your needs:
def compareFields( obj1, obj2, propName = null ) {
obj1.properties.each {
if ( it.value instanceof Object[] ) {
def obj2Len = obj2."${it.key}".length
it.value.eachWithIndex { collObj, idx ->
if ( idx + 1 <= obj2Len )
compareFields( collObj, obj2."${it.key}"[idx], "${it.key}[${idx}]" )
}
}
if ( !it.value.class.getCanonicalName().contains( 'java' ) ) {
compareFields( it.value, obj2."${it.key}", it.key )
}
if ( it.value.class.getCanonicalName().contains( 'java' ) &&
it.key != 'class' &&
it.value <=> obj2."${it.key}") {
println "${propName ? "$propName." : ''}${it.key}: '${it.value}' != '" + obj2."${it.key}" + "'"
}
}
}
Related
In my app I need to compile classes / scripts in runtime.
as a Class:
Class<? extends LoginAdapter> clazz = groovyClassLoader.loadClass name
LoginAdapter la = clazz.newInstance id, logo
or as a Closure:
Closure action = groovyShell.evaluate( script, name ) as Closure
Both ways work like charm.
Now I need to be able to write the compiled classes/scripts to some persistant storage (disc) and later restore them back without compiling from scratch.
How can this be done?
For those who might be interested, this is my programming kata:
class Base {
String answer() { null }
String question() { 'WHAT IS.... ?' }
}
class ClazzSpec extends Specification {
def "test compile"() {
given:
String packageName = 'some.pckg'
String body = """
package $packageName
class SomeClass extends Base {
Closure cl = { a -> println a }
#Override String answer(){ '42' }
String json( m ){ JsonOutput.toJson( m ) }
String longOne( int times ){
times.times{ sleep 100 }
'done'
}
}
"""
CompilerConfiguration cc = new CompilerConfiguration( targetDirectory:new File( './out' ) )
ImportCustomizer imp = new ImportCustomizer()
imp.addStarImports 'groovy.json', Base.package.name
cc.addCompilationCustomizers imp, new ASTTransformationCustomizer( value:1, TimedInterrupt )
new Compiler( cc ).compile packageName + '.SomeClass', body
File base = new File( './out' )
GroovyClassLoader gcl = new GroovyClassLoader()
gcl.addClasspath './out'
Class clazz = gcl.loadClass 'some.pckg.SomeClass'
when:
def inst = clazz.newInstance()
then:
inst.question() == 'WHAT IS.... ?'
inst.answer() == '42'
inst.json( [ q:42 ] ) == '{"q":42}'
inst.longOne( 2 ) == 'done'
when:
inst.longOne 11
then:
thrown TimeoutException
}
}
I am trying to determine the best way to return nested key values using groovy. If I have a map:
def map = [
OrganizationName: 'SampleTest',
Address: [
Street: '123 Sample St',
PostalCode: '00000',
]
]
Is there a way to return all of the keys? OrganizationName, OrganizationURL, Address.Street, Address.PostalCode? If I didn't have an map within a map I could use map.keySet() as String[]. Should I just loop through each key and see if it is an instanceof another map?
The Groovy libraries don't provide a method for this, but you can write your own. Here's an example that you can copy-paste into the Groovy console
List<String> getNestedMapKeys(Map map, String keyPrefix = '') {
def result = []
map.each { key, value ->
if (value instanceof Map) {
result += getNestedMapKeys(value, keyPrefix += "$key.")
} else {
result << "$keyPrefix$key"
}
}
result
}
// test it out
def map = [
OrganizationName: 'SampleTest',
Address: [
Street: '123 Sample St',
PostalCode: '00000',
]
]
assert ['OrganizationName', 'Address.Street', 'Address.PostalCode'] == getNestedMapKeys(map)
Use Following generic recursion Method To generate the list of all nested map keys
def getListOfKeys(def map, String prefix,def listOfKeys){
if(map instanceof Map){
map.each { key, value->
if(prefix.isEmpty()){
listOfKeys<<key
}else{
listOfKeys<< prefix+"."+key
}
if(value instanceof List){
List list = value
list.eachWithIndex { item, index ->
if(prefix.isEmpty()){
getListOfKeys(item, key+"["+index+"]",listOfKeys)
}else{
getListOfKeys(item, prefix+"."+key+"["+index+"]",listOfKeys)
}
}
}else if(value instanceof Map){
if(prefix.isEmpty()){
getListOfKeys(value, key,listOfKeys)
}else{
getListOfKeys(value, prefix+"."+key,listOfKeys)
}
}
}
}
}
call above method as follows
def void findAllKeysInMap(){
Map map = [ "fields":[
"project":
[
"key": "TP"
],
"summary": "Api Testing Issue.",
"description": "This issue is only for api testing purpose",
"issuetype": [
"name": ["Bug":["hello":[["saurabh":"gaur","om":"prakash"], ["gaurav":"pandey"], ["mukesh":"mishra"]]]]
]
]
]
def listOfKeys=[]
getListOfKeys(map, '', listOfKeys)
println "listOfKeys>>>"+listOfKeys
}
output:
listOfKeys>>>[fields, fields.project, fields.project.key, fields.summary, fields.description, fields.issuetype, fields.issuetype.name, fields.issuetype.name.Bug, fields.issuetype.name.Bug.hello, fields.issuetype.name.Bug.hello[0].saurabh, fields.issuetype.name.Bug.hello[0].om, fields.issuetype.name.Bug.hello[1].gaurav, fields.issuetype.name.Bug.hello[2].mukesh]
There's no such method You're looking for in groovy. You need to do it using instanceof and probably a recursive method.
Slightly shorter:
String key = 'Address.Street'
key.split('\\.').inject(yourMap) {map, path -> map[path]}
If you can't guarantee that the path exists and is complete (say, if you tried to access OrganizationName.id) you'll need to add some safeguards (check that map is not null, and that it's really a Map)
Imagine nodeBuilder used to express an object hierarchy:
class TestBuilder {
static main(args) {
def builder = new NodeBuilder()
def ulcDate = new Date(107,0,1)
def invoices = builder.invoices{
invoice(date: ulcDate){
item(count:5){
product(name:'ULC', dollar:1499)
}
item(count:1){
product(name:'Visual Editor', dollar:499)
}
}
invoice(date: new Date(106,1,2)){
item(count:4) {
product(name:'Visual Editor', dollar:499)
}
}
}
}
class Invoice {
List items
Date date
}
class LineItem {
Product product
int count
int total()
{
return product.dollar * count
}
}
class Product {
String name
def dollar
}
How do I actually convert invoices object, which was generated by NodeBuilder, to an instance of Invoice class with everything configured from the invoices object? I probably have to have use GPath to do so (?) but how would that code look like?
The reason that I need to do so is that the other methods of other classes require an instance of the Invoice class to operate further and won't accept a NodeBuilder output I guess.
I think the easiest way is simply to do node traversal for your particular set of objects.
Example:
import groovy.util.*
////////////
// build Node tree as asked in original post
def builder = new NodeBuilder()
def ulcDate = new Date(107,0,1)
def invoices = builder.invoices {
invoice(date: ulcDate) {
item(count:5) {
product(name:'ULC', dollar:1499)
}
item(count:1) {
product(name:'Visual Editor', dollar:499)
}
}
invoice(date: new Date(106,1,2)){
item(count:4) {
product(name:'Visual Editor', dollar:499)
}
}
}
////////////
// define objects. It is easy to have these in Java
class Invoice {
def date
def items = []
}
class Item {
def count
def product
}
class Product {
def name
def dollar
}
////////////
// convert from nodes to objects
def invoiceNodeList = invoices.get("invoice")
def invoiceList = []
invoiceNodeList.each { def invoiceNode ->
def date = invoiceNode.attribute("date")
Invoice invoice = new Invoice(date: date)
invoiceNode.children().each { def itemNode ->
def count = itemNode.attribute("count")
Product product = null
// assume only one Product per Item, but we'll
// use children() for simplicity
itemNode.children().each { def productNode ->
def name = productNode.attribute("name")
def dollar = productNode.attribute("dollar")
product = new Product(name: name, dollar: dollar)
}
Item item = new Item(count: count, product: product)
invoice.items << item
}
invoiceList << invoice
}
////////////
// print out objects
invoiceList.each { Invoice invoice ->
println "--------"
println invoice.date
invoice.items.each { Item item ->
println item.count
println item.product.name
println item.product.dollar
}
}
Giving a slight tweak to your base classes:
class Invoice {
List lineItems = []
Date date
String toString() {
String ret = "Invoice $date $lineItems"
}
}
class LineItem {
Product product
int count
int total() {
product.dollar * count
}
String toString() {
"$product * $count"
}
}
class Product {
String name
int dollar
String toString() {
"$name ($dollar)"
}
}
Means you can easily use ObjectGraphBuilder to build your list:
List invoices = new ObjectGraphBuilder(classLoader: getClass().classLoader).with {
[
invoice( date: new Date( 107, 0, 1 ) ) {
lineItem( count: 5 ) {
product( name: 'ULC', dollar: 1499 )
}
lineItem(count:1){
product(name:'Visual Editor', dollar:499)
}
},
invoice(date: new Date(106,1,2)){
lineItem(count:4) {
product(name:'Visual Editor', dollar:499)
}
}
]
}
If it isn't possible to tweak the base classes, you can customise how properties are looked up by setting the resolvers before building your graph
I want to use either a value of expected property or a specified default.
How to achieve this in groovy?
Let's look at the example:
def printName(object) {
//if object has initialized property 'name' - print 'name', otherwise print ToString
if (object<some code here>name && object.name) {
print object.name
} else {
print object
}
}
You can use hasProperty. Example:
if (object.hasProperty('name') && object.name) {
println object.name
} else {
println object
}
If you're using a variable for the property name, you can use this:
String propName = 'name'
if (object.hasProperty(propName) && object."$propName") {
...
}
Assuming your object is a Groovy class, you can use hasProperty in the object metaClass like so:
def printName( o ) {
if( o.metaClass.hasProperty( o, 'name' ) && o.name ) {
println "Printing Name : $o.name"
}
else {
println o
}
}
So, then given two classes:
class Named {
String name
int age
String toString() { "toString Named:$name/$age" }
}
class Unnamed {
int age
String toString() { "toString Unnamed:$age" }
}
You can create instance of them, and test:
def a = new Named( name: 'tim', age: 21 )
def b = new Unnamed( age: 32 )
printName( a )
printName( b )
Which should output:
Printing Name : tim
toString Unnamed:32
You can write your own method via meta-programming:
class Foo {
def name = "Mozart"
}
def f = new Foo()
Object.metaClass.getPropertyOrElse = { prop, defaultVal ->
delegate.hasProperty(prop) ? delegate."${prop}" : defaultVal
}
assert "Mozart" == f.getPropertyOrElse("name", "")
assert "Salzburg" == f.getPropertyOrElse("city", "Salzburg")
If I simply want to assert that an object has some property, I just test the following:
assertNotNull(myObject.hasProperty('myProperty').name)
If myObject does not have myProperty the assertion will fail with a null pointer exception:
java.lang.NullPointerException: Cannot get property 'name' on null object
Is there a way in groovy to do something like:
class Person{
def name, surname
}
public void aMethod(anoherBean){
def bean = retrieveMyBean()
p.properties = anoherBean.properties
}
The property properties is final, is there another way to do this shortcut?
properties is a virtual property; you have to call the individual setters. Try this:
def values = [name: 'John', surname: 'Lennon']
for( def entry : values.entries() ) {
p.setProperty( entry.getKey(), entry.getValue() );
}
Or, using MOP:
Object.class.putAllProperties = { values ->
for( def entry : values.entries() ) {
p.setProperty( entry.getKey(), entry.getValue() );
}
}
Person p = new Person();
p.putAllProperties [name: 'John', surname: 'Lennon']
[EDIT] To achieve what you want, you must loop over the properties. This blog post describes how to do that:
def copyProperties(def source, def target){
target.metaClass.properties.each{
if (source.metaClass.hasProperty(source, it.name) && it.name != 'metaClass' && it.name != 'class')
it.setProperty(target, source.metaClass.getProperty(source, it.name))
}
}
If you don't have any special reason then just use named parameters
def p = new Person(name: 'John', surname: 'Lennon')
After question being updated
static copyProperties(from, to) {
from.properties.each { key, value ->
if (to.hasProperty(key) && !(key in ['class', 'metaClass']))
to[key] = value
}
}