Custom Expression Language

Hey all,

I’d like to share a nice trick for implementing a custom Expression Langauge, which is just a fancy term for replacing String (or substring) values with variables at runtime. In most cases, including in Katalon Studio, this is done with the dollar-sign notation:

“Hello world, my name is ${name}.”

At runtime, we would pass this to some interpreter (usually this is done behind the scenes in Katalon, say, when you call a parameterized Test Object), and any substring of the format ${} would be replaced with some other value.

This currently works in a lot of places in Katalon Studio, but it doesn’t work in Test Data (maybe it should? perhaps a feature request is in order…). As such, we’ve been using a custom EL interperter. In our case the values being replaced are method/function calls, so the expected format is ${someFunction(arg1, arg2, ...)}, but this could easily be adapted to handle static values, including GlobalVariables:

public static String getELValue(final String value) {
	int occurrence = value.indexOf("\${");
	if(occurrence >= 0) {
		String expression = value.substring(occurrence, value.indexOf("}") + 1);
		String function = expression.substring(2, expression.indexOf("("));
		String[] arguments = expression.substring(expression.indexOf("(") + 1, expression.indexOf(")")).split(",");
		String replacement = "INVALID_FUNCTION";
		switch(function) {
			case "randomAlphanumeric":
				replacement = Functions.randomAlphanumeric(Integer.parseInt(arguments[0]));
				break;
			case "randomString":
				replacement = Functions.randomString(Integer.parseInt(arguments[0]));
				break;
			case "randomNumber":
				replacement = Functions.randomNumber(Integer.parseInt(arguments[0]));
				break;
			case "randomCharSequence":
				replacement = Functions.randomCharSequence(Integer.parseInt(arguments[0]), arguments[1]);
				break;
			case "todaysDate":
				replacement = Functions.todaysDate(Integer.parseInt(arguments[0]));
				break;
			case "timestamp":
				replacement = Functions.timestamp();
				break;
		}
		return getELValue(value.replace(expression, replacement));
	}
	return value;
}

This method uses recursion so that multiple variables could be placed in the String. So, for instance, I could have a value in my data file like this:

“The current date is ${todaysDate()}, and the current timestamp is ${timestamp()}”

And if i passed this value to that method, the returned string would be something like:

“The current date is 05/20/2020, and the current timestamp is 134897012341234”

4 Likes