how to expand #137b866 in soap ui using groovy? - groovy

in soap ui we usually get values like
"com.eviware.soapui.impl.wsdl.teststeps.WsdlGroovyScriptTestStep#137b866"
what does it mean and how can we expand it?

That means you have an instance of WsdlGroovyScriptTestStep
So you should be able to just call the methods in the documentation I linked to, ie:
obj.description
(which will call getDescription())

This means that you have an object which is an instance of this class, and probably you're invoking toString() method on this object, by default if you don't override toString() method on specific object you get objectClassName#hashcodenumber.
If you want to see the WsdlGroovyScriptTestStep methods you can take a look on the API. However if you want to see dynamically a list of all methods for an specific object with groovy, you can do it in a java way using reflection. For example if you have an object instance of some class you can get the class obj.getClass()an invoking obj.getClass().getMethods() or obj.getClass().getDeclaredMethods() in this object you get a list of all of its methods. See the example below:
def obj = 'sample test'
// Returns an array of Method objects reflecting all the methods declared by the class
// or interface represented by this Class object. (from java API)
def declaredMethods = obj.getClass().getDeclaredMethods()
// Returns an array containing Method objects reflecting all the public member methods
// of the class or interface represented by this Class object, including those declared
// by the class or interface and those inherited from superclasses and superinterfaces.
def methods = obj.getClass().getMethods()
log.info "DECLARED METHODS"
// print the method names
for(declaredMethod in declaredMethods){
log.info declaredMethod
}
log.info "METHODS"
// print more method names
for(method in methods){
log.info method
}
// i.e invoke indexOf(int) using reflection
def classArray = new Class[1]
classArray[0] = String.class
def indexOfMethod = obj.getClass().getDeclaredMethod("indexOf", classArray)
def result = indexOfMethod.invoke(obj,'test')
log.info "using reflection: 'sample test'.indexOf('test') =" + result
log.info "normal invocation: 'sample test'.indexOf('test') =" + obj.indexOf('test')
(I use log.info in the sample because I executed in soapui groovy testStep)
Hope this helps,

Related

Groovy - How to serialize an object into a string

How to serialize an object into a string
below is the .net code for serializing an object into a string
String sampleEntity= JsonConvert.SerializeObject(entity))
same I need it in groovy? please suggest
Assuming entity is some object or list of objects, the easiest way IMO is:
import groovy.json.*
class Person { // this is a sample object, like entity in your example
String name
}
def json = JsonOutput.toJson([ new Person(name: 'John'), new Person(name: 'Max') ])
println json​
// output (string): [{"name":"John"},{"name":"Max"}]
If you need to customize the output (like fiddle with exact format of dates or something), you should use JsonGenerator Instead. It has a builder that will allow to do this fine grained setup. Since its a kind of beyond the scope of the question, I'll just provide a link to the relevant chapter of documentation

Accessing a variable defined in another function in Groovy

I am new to Groovy.
I have a function in which I am writing a value to map.
def addTraceEntry(key, value) {
def traceability = [:]
traceability[key] = value.trim()
println "This print happens in function addTraceEntry " + traceability
}
I have another function that needs to verify whether the above function works properly.
def testAddTraceEntry() {
def key = 'test_key'
def value = 'test_value'
addTraceEntry(key, value)
println "This print happens in function testAddTraceEntry " + traceability
assert value == traceability[key]
}
I am invoking the testAddTraceEntry() function using the function name:
testAddTraceEntry()
When I run this, I get the ERROR:
This print happens in function addTraceEntry [test_key:test_value]
Caught: groovy.lang.MissingPropertyException: No such property: traceability for class: HelloWorld
groovy.lang.MissingPropertyException: No such property: traceability for class: HelloWorld
at HelloWorld.testAddTraceEntry(HelloWorld.groovy:53)
at HelloWorld.run(HelloWorld.groovy:57)
In the function testAddTraceEntry it clearly does not know the value of traceability so seems like its giving an ERROR for that.
I tried to return the value of traceability.
def addTraceEntry(key, value) {
def traceability = [:]
traceability[key] = value.trim()
println "This print happens in function addTraceEntry " + traceability
return traceability
}
But this yields the same ERROR.
There are a bunch of things worth mentioning after seeing the code you have wrote.
First thing - the scope of variables and encapsulation. Let's throw away technicalities for a moment and focus on something even more important. In method addTraceEntry you persist some state, which is fine. However, the implementation of the method testAddTraceEntry reveals that this method tries to know way to much about the implementation details of addTraceEntry. It encapsulates (hides in other words) persistence logic (from the API point of view you, as a caller, don't know that it persists key and a value inside the map) and that is why testAddTraceEntry should never ever make assumptions that calling this method mutated some structure. If you do so, then:
your test method contracts side effects and not the expected business logic (storing data in some kind of global map - don't do it. Ever)
your test blocks any evolution of tested method implementation - imagine, that you decided to store key and value in a different structure. You may do it without breaking any API contract (your function produces the same results), but the test method will fail and you will have to modify it.
Second thing - your addTraceEntry method always produces a map with a single entry. It doesn't make much sense and if you call your function let's say 4 times you will end up with 4 maps where each one of them contain a single key mapped to a single value.
There are at least various ways to improve implementation of your methods. The simplest thing you can do is to implement a class that encapsulates logic for storing keys and values. Consider following example:
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
class TraceEntriesStorage {
private final ConcurrentMap<String, Object> entries = [:] as ConcurrentHashMap
def addTraceEntry(String key, Object value) {
entries.put(key, value)
}
def containsTraceEntry(String key) {
return entries.containsKey(key)
}
def retrieveTraceEntryForKey(String key) {
return entries.get(key)
}
}
This is a simple class with 3 short methods. It stores trace entries inside the internal concurrent map (to solve problems with concurrent access). Now, your test method could look like this:
def storage = new TraceEntriesStorage()
storage.addTraceEntry("test_key", "test_value")
assert storage.containsTraceEntry("test_key")
assert storage.retrieveTraceEntryForKey("test_key") == "test_value"
You create an instance of this class, you add an entry and you check if methods containsTraceEntry and retrieveTraceEntryForKey return expected values. As you can see it doesn't matter where we stored this trace entry - it matters that the class we have implemented behaves as expected. To make this test method even better you could add an assertion that checks if there is no trace entry for test_key before we actually insert it - this way we know that adding trace entry change internal state of the class. But what is nice in this approach is that as long as we don't break the contract, we can experiment and modify implementation of TraceEntriesStorage. Because what is most important - adding trace entries have to allow to retrieve them back from the object. How it gets stored, where it gets stored - it doesn't matter.
I hope you find this answer useful and it will help you in learning Groovy and designing a better programs. Happy hacking!
You need to combine adding the return statement to addTraceEntry() with assigning the returned value to a variable in testAddTraceEntry():
def traceability = addTraceEntry(key, value)

Nomin automap causes infinite loop

I am using Nomin for mapping tasks. As taken from the documentation of Nomin it should be able to map fields with the same name by itself in case automapping has been activated. When activating it, it causes an infinite loop exception.
I have the following:
mappingFor a: CoinsOnMarketPlace, b: Coin
// automap() // when deactivated it works fine, when activated infinite loop
a.coin.name = b.name
a.coin.rank = b.rank
a.priceUSD = b.priceUSD // Could be automapped
a.priceBTC = b.priceBTC // Could be automapped
...
Exception:
org.nomin.core.NominException: ./net/hemisoft/ccm/repository/coinmarketcap2coin.groovy: Recursive mapping rule a = b causes infinite loop!
One thing worth adding regarding your use case - this Recursive mapping rule a = b causes infinite loop! exception is thrown because you use groovy classes in your mapping rule. Nomin uses ReflectionIntrospector and what's important:
It performs getting/setting properties using accessor methods which are called through the Java reflection mechanism. ReflectionIntrospector uses supplied NamingPolicy instance to determine accessor methods. JbNamingPolicy is used by default, this implementation cerresponds the JavaBeans convention. Its InstanceCreator named ReflectionInstanceCreator instantiates objects using Class.newInstance().
Source: http://nomin.sourceforge.net/introspectors.html
A simple Groovy class like:
class Entity {
String name
String somethingElse
}
gets compiled to a Java class that implements GroovyObject providing following methods:
public interface GroovyObject {
Object invokeMethod(String var1, Object var2);
Object getProperty(String var1);
void setProperty(String var1, Object var2);
MetaClass getMetaClass();
void setMetaClass(MetaClass var1);
}
In this case ReflectionInstanceCreator combined with automap() resolves following mappings:
a.property = b.property
and
a = b
where a = b mapping comes from MetaClass getMetaClass() getter method I suppose, because there is no mapping like a.metaClass = b.metaClass resolved. a.property = b.property gets resolved because of Object getProperty(String var1) method.
Solution
This problem can be solved by specifying explicitly ExplodingIntrospector for your mapping script that:
It performs getting/setting properties using a class field immediately through through the Java reflection mechanism and may be useful in case when domain object don't provide accessors for their properties. Supplied instance creator is ReflectionInstanceCreator.
Source: http://nomin.sourceforge.net/introspectors.html
All you have to do is to add
introspector exploding
right below mappingFor a: ..., b: ... header. For example:
import mypackage.Entity
import mypackage.EntityDto
mappingFor a: Entity, b: EntityDto
introspector exploding
automap()
a.test2 = b.test1
Tested with two Groovy classes, worked like a charm. Hope it helps.

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?;-)

Can I do this with ExpandoMetaClasses in Groovy?

When upgrading from Groovy 1.8.4 to 1.8.5 the JsonSlurper returns a BigDecimal instead of a float or double for numbers in Json. For example consider the following JSON document:
{"person":{"name":"Guillaume","age":33.4,"pets":["dog","cat"]}}
In Groovy 1.8.4 "age" would be represented as a float whereas in Groovy 1.8.5+ it's represented as a BigDecimal. I've created a Java framework that uses the Groovy JsonSlurper under the hood so in order to maintain backward-compatibility I'd like to convert JSON numbers (such as 33.4) to float or double transparently. Having looked at the groovy-json source code I see that JsonSluper uses a JsonToken which is the one that creates a BigDecimal out of 33.4 in its "getValue()" method. This method is called by the JsonSlurper instance.
So what (I think) I want to do is to override the getValue() method in the JsonToken class to have it return a float or double instead. This is what I've tried:
def original = JsonToken.metaClass.getMetaMethod("getValue")
JsonToken.metaClass.getValue = {->
def result = original.invoke(delegate)
// Convert big decimal to float or double
if (result instanceof BigDecimal) {
if (result > Float.MAX_VALUE) {
result = result.doubleValue();
} else {
result = result.floatValue();
}
}
result
}
The problem is that even though the code stated above is executed before new JsonSluper().parseText(..) the overridden "getValue()" in JsonToken is not called (the original getValue() method is called instead). But if I copy all code from the JsonSlurper class into my own class, let's call it JsonSlurper2, and do new JsonSluper2().parseText(..) the overridden method of "getValue()" is called and everything works as expected. Why is this? What would I have to do to avoid copying JsonSlurper to my own class?
JsonSlurper is a Java class and therefore you are unable to override its methods via metaClass. See this mailing list thread.
This question looks like it might have a way for you to do this.

Resources