back
Avatar of Pascal Bihler
Author: Pascal Bihler
04. July 2019

News about the print(…) and println(…) module

If you are working with QF-Test scripting nodes, no matter whether you prefer Jython, Groovy or JavaScript, you will come across the QF module sooner or later. This module, accessible in all script nodes and script terminals via the variable qf, holds a bunch of helper methods designed to make the life of a script programmer easier.

From time to time the module will be enhanced by new methods - in QF-Test 4.6.0 by the methods  print and println. A good opportunity to have a look at the module and its new methods.

qf.print(ln)

The method qf.print(…) prints a string (resp. the string value of an object) to the QF-Test terminal (and with SUT scripts also to the client terminal). qf.println(…) adds a line break to the output to ensure the next output will be printed to a new line. But why not just use a simple  print (without qf. in front)?

Theoretically yes, but... The classic print writes a string to the so-called Standard Output of the program. QF-Test intercepts the string and redirects it to the terminal. Usually, this works all right, however, especially with SUT scripts, you might run into the problem that the client application itself redirects the Standard Output thus preventing QF-Test ever to 'see' the output. This can become really annoying when you need to resort to the classic 'print debugging' when writing resolvers.

qf.print(…) skirts the problem, not transmitting the string via the normal output channels, but sending it 'directly' via the internal RMI interface (i.e. via the same 'line' QF-Test uses to control the SUT and to send values for checks and events). Now, client specific adaptions will not matter anymore and on top it is slightly more efficient.

The small print

I would like to go into detail with some side effects:

 

1. qf.print(…) does not only take one parameter but as many as you like and joins them by space characters. This little JavaScript program:

const x = 1
const y = 1
const z = x + y
qf.println(x,y,z)

will produce the terminal output '1 1 2'.

2. qf.print(…)calls the Java string method toString() to generate the output. So, if you have been trying in vain to check whether the  Jython array module really produces a Java array:

import array
from java.lang import String
 
print array.array(String,("a","b","c")) # array(java.lang.String, [u'a', u'b', u'c'])

qf.println(…) will now be a solution:

import array
from java.lang import String
 
qf.println(array.array(String,("a","b","c"))) # [Ljava.lang.String;@353191ee


The first script will print a Jython string representation of the array ("When an array object is printed or converted to a string, it is represented as array(typecode, initializer). "), however not representing the view of Java on the object. The second script will print the output of toString() for Java arrays, i.e. the type information and its hash code (just for once this output will prove helpful in order to check it is a real Java array. In the Java world you would rather prefer Arrays.deepToString(a) to see the content). If you want to print the Jython string representation just add  str(…): qf.println(str(array.array(String,("a","b","c")))).

3. Like the other 'standard' variables (rc, out, resolvers, notifications, …) with Groovy scripts qf principally only works on top level:

class InnerClass {
    def printSomething() {
        println("Something")
    }
     
    def printSomethingElse() {
        qf.println("SomethingElse")
    }
}
 
def c = new InnerClass()
 
c.printSomething() // => Does not reach the terminal in a Server-Script nicht im Termial an, because "println" directly uses the standard output.
c.printSomethingElse() // => "No such property: qf for class: InnerClass"

To get around this, you can transfer the bindings via the contructor to the inner class:

class InnerClass {
    
    def out,qf
     
    def printSomething() {
        out.println("Something")
    }
     
    def printSomethingElse() {
        qf.println("SomethingElse")
    }
}
 
def c = new InnerClass(out:out,qf:qf)
 
c.printSomething()
c.printSomethingElse()

simple and effective, especially when writing your own checker or when updating older resolvers.

New comment
( Will be displayed on the page )
( Will not be displayed on the page )

1 comments

Robert Lahmer

03. December 2020

Hi Pascal,

 

it is true that InnerClass does not know 'out' and 'qf', but instead of providing both in the constructor, you could also extend the class dynamically in Groovy using its metaClass, for example

 

class InnerClass { ... }

 

InnerClass.metaClass.qf = qf

InnerClass.metaClass.println = {

println(it)

}

 

def c = new InnerClass()

c.printSomething() // println does use 'out' now

c.printSomethingElse() // qf is now a known property

 

 

Best regards,

Robert