Test case script, variables and setup / teardown methods

This is the very simplified case:

@SetUp(skipped = false) 
void setup() {
	println uniqueString
}

@Field long ts = System.currentTimeMillis()
@Field final String uniqueString = "MyString_" + ts

@TearDown(skipped = false) 
void teardown() {
	println uniqueString
}

Outputs:

MyString_1552654853710
MyString_1552654853726

One would say that final variable is not changed after it is declared, but it is.
Basically I need the same value in both setup and teardown methods, it looks like teardown() method re-initialize all the variables when it is invoked. Any Groovy experts around? :slight_smile:

Hey Marek (good to see you around again!)

I had something similar but my issue appeared in a listener, not in setup/teardown.

The variable was a static in a class imported statically.

The value was assigned in the listener. But by the time I came to reuse the variable (in a TC for example) it had been cleared.

The solution I found was, in the listener, call a static method in the same class where the var was defined and pass the value in to be assigned. Then the var seemed to survive.

Not sure if that helps your situation. Not sure if the setup/teardown hooks are happening in the right place to help here. There was certainly something weird about the listener hooks.

Hey Russ, nice to see you again, I needed a short break, but I am back. :muscle:

This is my crappy, but working solution.

@SetUp
void setup() {
	 KeywordUtil.logInfo("Setup test: " + myId)
}

@Field String myId = DynamicIdGenerator.getInstance().getDynamicVariableByClassName(getClass())

@TearDown
 void teardown() {
	 KeywordUtil.logInfo("Teardown test: " + myId)
}

Generator class:

public class DynamicIdGenerator {
	static long dynamicVar = System.currentTimeMillis()
	static DynamicIdGenerator instance = null
	
	private DynamicIdGenerator() {}
	
	public static DynamicIdGenerator getInstance() {
		if(instance == null) {
			instance = new DynamicIdGenerator()
		}
		return instance
	}
	public static String getDynamicVariableByClassName(Class<Object> o) {
		return o.getName() + "_" + dynamicVar
	}
}

Why?
This solution is:

  • unique for every test case (script / class name is a part of a variable)
    AND
  • unique for every run of the test case (timestamp)

This works for:

  • sequential tests execution within test suite
    – the only exception seems to be when one test is present 2 or more times in the single test suite
    – when retry failed tests is active, it works as well
  • parallel test suites execution
    – it looks like Katalon uses thread-safe runner, which makes singleton class unique for the test suite

I know that this is very crappy solution for such a basic thing, but I spent hours looking for easier and straight-forward solution, but, unfortunately, Katalon/Groovy does not offer any.

2 Likes

Hmm. I would expect that to work. Did you find out why it seems to fail? It seems that might suggest myId is instantiated only once for any repeated TC, which I find surprising. But if this is indeed true, then would this work…?

@Field String myId = ""

@SetUp
void setup() {
  myId = DynamicIdGenerator.getInstance().getDynamicVariableByClassName(getClass())       
  KeywordUtil.logInfo("Setup test: " + myId)
}

@TearDown
void teardown() {
  KeywordUtil.logInfo("Teardown test: " + myId)
}

Well, it does not fail, but the value is the same (and you want unique value in every single case). But it is more like by design of this solution.

My observation (not necessarily correct) is that setup and teardown methods take the variable as-is in the script.

So:

  • when you declare a variable in a script and initialize in setup(),
    the value is assigned in setup(), but not in script
  • when you declare and initialize a variable in a script,
    the value is assigned and available in both setup() and teardown()

The only problem here is the dynamic part of variable. You must:

  • declare and initialize variable(s) in the script itself
    AND
  • make sure that dynamic value is unchanged

As soon as you use
long ts = System.currentTimeMillis()
setup() assigns current time to a variable, you do your things in a test and teardown() does the very same, it assigns current time, but not the same as before (your test takes XY seconds).

And this is very confusing for me, why the state of variables is changing at different test stages. For some reason, variables are re-initialized every time you call setup or teardown. Maybe the logic behind annotation would explain it.

Yes, I understood this from your first post. It’s certainly not ideal behavior and counter-intuitive. There must be a single place on a TC single-instance basis for setting stuff like this (without having to tinker around with overriding invokeMethod or other stuff like that).

@devalex88 - any ideas?

2 Likes

Any updates? Is this issue going to be fixed?