I could definitely use some help here. I have an excel sheet from where I am getting values and doing some validations on them, I am checking if both values match. My code is as follows:
#Unroll ("For #calcToCheck.tr_date_class")
def "I check flag value #calcToCheck.tr_date "(CalculationClass calcToCheck) {
expect:
flag==calcToCheck.result
where:
calcToCheck << calInputParameters()
}
def calInputParameters() {
//some logic to get values from SQL and getting flag
return calcsToCheck
}
This runs fine for one row but when I insert multiple rows in excel sheet, I just get output as one result. I would like to see each row's result. I thought adding #Unroll would take care of it showing me what rows it is displaying the results but it does not.
Here is some sample code you can run and then modify. Because you did not explain where flag comes from, I was just making up something, assuming it is also an unrolled parameter checked against whatever your helper method delivers.
package de.scrum_master.stackoverflow
import spock.lang.Specification
import spock.lang.Unroll
/**
* See https://stackoverflow.com/q/48410722/1082681
*/
class PseudoExcelTableTest extends Specification {
#Unroll//("For #calcToCheck.tr_date_class")
def "I check flag value #calcToCheck.tr_date"(CalculationClass calcToCheck, int flag) {
expect:
flag == calcToCheck.result
where:
calcToCheck << calInputParameters()
flag << [11, 22, 33]
}
def calInputParameters() {
def calcsToCheck = new ArrayList<CalculationClass>()
calcsToCheck.addAll(
new CalculationClass(result: 11, tr_date: "eleven", tr_date_class: "short"),
new CalculationClass(result: 22, tr_date: "twenty-two", tr_date_class: "long"),
new CalculationClass(result: 33, tr_date: "thirty-three", tr_date_class: "normal")
)
return calcsToCheck
}
static class CalculationClass {
int result
String tr_date
String tr_date_class
}
}
As for the unrolled method names, you mix up two things:
Naming the methods via #Unroll parameter, which in my example would result in method names For short, For long, For normal. This has preference over the second option:
Naming the methods via normal method name, which in my example would result in method names I check flag value eleven, I check flag value twenty-two, I check flag value thirty-three.
I chose option 2 by commenting out the unroll parameter.
Related
I noticed that when calling values() or values_list() one a queryset returns the normal value in the field and not the display value I'd like. Is there a way to manupilate the display value of the field while creating a result that is a list of list of the queryset?
class FooBar(models.Model):
...
foo_bar = models.CharField(_("foo"), choices=[(1, 'foo'), (2, 'bar')])
def get_foo_bar_display(self):
return "something"
def get_foobar(user):
foobar = FooBar.objects.filter(user=user).values_list(.., 'foo_bar')
foobar = list(map(list, foobar))
return foobar
It always returns the foo_bar original value and not the display value.
One way out for you is to get the model instances with only some selected fields (needed for the get_x_display to work correctly) using .only() query set method.
Going from there you can call the get_x_display on the model like you'd normally do.
I would like to know if it is possible to retrieve the name of a variable.
For example if I have a method:
def printSomething(def something){
//instead of having the literal String something, I want to be able to use the name of the variable that was passed
println('something is: ' + something)
}
If I call this method as follows:
def ordinary = 58
printSomething(ordinary)
I want to get:
ordinary is 58
On the other hand if I call this method like this:
def extraOrdinary = 67
printSomething(extraOrdinary)
I want to get:
extraOrdinary is 67
Edit
I need the variable name because I have this snippet of code which runs before each TestSuite in Katalon Studio, basically it gives you the flexibility of passing GlobalVariables using a katalon.features file. The idea is from: kazurayam/KatalonPropertiesDemo
#BeforeTestSuite
def sampleBeforeTestSuite(TestSuiteContext testSuiteContext) {
KatalonProperties props = new KatalonProperties()
// get appropriate value for GlobalVariable.hostname loaded from katalon.properties files
WebUI.comment(">>> GlobalVariable.G_Url default value: \'${GlobalVariable.G_Url}\'");
//gets the internal value of GlobalVariable.G_Url, if it's empty then use the one from katalon.features file
String preferedHostname = props.getProperty('GlobalVariable.G_Url')
if (preferedHostname != null) {
GlobalVariable.G_Url = preferedHostname;
WebUI.comment(">>> GlobalVariable.G_Url new value: \'${preferedHostname}\'");
} else {
WebUI.comment(">>> GlobalVariable.G_Url stays unchanged");
}
//doing the same for other variables is a lot of duplicate code
}
Now this only handles 1 variable value, if I do this for say 20 variables, that is a lot of duplicate code, so I wanted to create a helper function:
def setProperty(KatalonProperties props, GlobalVariable var){
WebUI.comment(">>> " + var.getName()" + default value: \'${var}\'");
//gets the internal value of var, if it's null then use the one from katalon.features file
GlobalVariable preferedVar = props.getProperty(var.getName())
if (preferedVar != null) {
var = preferedVar;
WebUI.comment(">>> " + var.getName() + " new value: \'${preferedVar}\'");
} else {
WebUI.comment(">>> " + var.getName() + " stays unchanged");
}
}
Here I just put var.getName() to explain what I am looking for, that is just a method I assume.
Yes, this is possible with ASTTransformations or with Macros (Groovy 2.5+).
I currently don't have a proper dev environment, but here are some pointers:
Not that both options are not trivial, are not what I would recommend a Groovy novice and you'll have to do some research. If I remember correctly either option requires a separate build/project from your calling code to work reliable. Also either of them might give you obscure and hard to debug compile time errors, for example when your code expects a variable as parameter but a literal or a method call is passed. So: there be dragons. That being said: I have worked a lot with these things and they can be really fun ;)
Groovy Documentation for Macros
If you are on Groovy 2.5+ you can use Macros. For your use-case take a look at the #Macro methods section. Your Method will have two parameters: MacroContext macroContext, MethodCallExpression callExpression the latter being the interesting one. The MethodCallExpression has the getArguments()-Methods, which allows you to access the Abstract Syntax Tree Nodes that where passed to the method as parameter. In your case that should be a VariableExpression which has the getName() method to give you the name that you're looking for.
Developing AST transformations
This is the more complicated version. You'll still get to the same VariableExpression as with the Macro-Method, but it'll be tedious to get there as you'll have to identify the correct MethodCallExpression yourself. You start from a ClassNode and work your way to the VariableExpression yourself. I would recommend to use a local transformation and create an Annotation. But identifying the correct MethodCallExpression is not trivial.
no. it's not possible.
however think about using map as a parameter and passing name and value of the property:
def printSomething(Map m){
println m
}
printSomething(ordinary:58)
printSomething(extraOrdinary:67)
printSomething(ordinary:11,extraOrdinary:22)
this will output
[ordinary:58]
[extraOrdinary:67]
[ordinary:11, extraOrdinary:22]
I have a simplified test scenario created where I have a spreadsheet with two cells (C2/C3) having an array formula:
{=NaNTest()}
My simplified CustomFunction is as follows:
public class NaNTest : CustomFunctions.Function
{
public NaNTest() : this( "NaNTest" ) { }
public NaNTest( string name ) : base( name, CustomFunctions.Volatility.Invariant, CustomFunctions.ValueType.Variant ) { }
public override void Evaluate( CustomFunctions.IArguments a, CustomFunctions.IValue r )
{
var result = new double[ 1, 2 ];
result[ 0, 0 ] = double.NaN;
result[ 0, 1 ] = 0d;
r.SetArray( result );
}
}
This sets both C2 and C3 to #NUM! when I'd expect only C2 to be. Is there a way to make it correctly* assign C3 to 0?
Thanks in advance.
* I say correctly because we have to implement an Excel add-in that our clients use to author spreadsheets and it provides same 'functionality' that we provide on 'our servers' when we open/process the spreadsheet in our 'SpreadsheetGear calculations' (i.e. the NaNTest() function above). The libraries we use to create the add-in only assign C2 to #NUM! and having the two implementations (client side add-in vs server side SpreadsheetGear) behaving differently makes maintenance/debugging difficult.
This behavior is by design. Note the comment in the documentation for the IValue.SetArray(...) method:
If any of the numbers in the array are not valid numbers, the result
of the custom function will be ValueError.Num.
Since NaN isn't a valid number the entire array will resolve to #NUM! instead. Actually, if you try to set a cell value on its out (outside of a custom function), such as...
worksheet.Cells["A1"].Value = double.NaN;
...you should find that cell evaluates to #NUM! as well. If such cases can occur in your custom function, you'll likely just need to write a check for this condition and respond in whatever manner is required by your application.
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.
For a unit test I want to use the Range attribute from NUnit to test inputs to a function in a range. The lower and upper limits of this range are coded into constant properties of a (Singleton pattern) class. I would like to specify the starting point and end point of the Range attribute with the class properties, something like this:
[Test]
public void sometest([Range(MyClass.LOWER_LIMIT,MyClass.UPPER_LIMIT)] int var)
{
//Do something and assertive with the nice variable
}
However, this approach does not work. Although it is not clear from the documentation itself, it seems that the Range attribute must be provided constant variables. While my class constants are static properties with only get defined, this does capture a constant variable.
I posted and answer to this question, but is this really the way to set the range parameters based on class constant in NUnit? Or is there a more elegant solution?
The following example demonstrates how one can use (constant)properties from a class as values used with the Range attribute from NUnit.
const int LO_LIM = 1;
const int HI_LIM = 10;
[Test]
public void assertConstantsCorrect()
{
//Will fail if constants change during development!
Assert.AreEqual(MyClass.LOWER_LIMIT,LO_LIM);
Assert.AreEqual(MyClass.UPPER_LIMIT,HI_LIM);
}
[Test]
public void sometest([Range(LO_LIM,HI_LIM)] int var)
{
//Do test
}
The first step is to define constants in your test class, as the Range attribute only works with constants. These constants take the same values as the constants defined in the properties of your class.
Second is a Test created to verify that they correspond. If at a later date and time the constants in MyClass change, the failure in this test will notify you of this change. Take note that if this test does not pass, any other test using those constants can be regarded as invalid as they rely on false asumptions!
Lasty are your actual tests that use those values in the [Range( start, end)] clause.
Alternatively, you can also make use the [TestFixtureSetUp] attribute instead of the [Test] attribute for the assertConstantsCorrect() method to make all tests in the fixture fail in case the assertConstantsCorrect() fails.
Yet another alternative is to make a custom attribute to work for specific methods you as programmer annotate and make those methods fail when assertConstantsCorrect() fails.