Please help me how to verify if sorting of alphanumeric with symbol character values in data table is correct. Sample values are: AA-1, AA-10, AA-2, AA-2 (1)
When clicking the column header to sort it as ascending, the web application displays it as:
AA-1
AA-2
AA-2 (1)
AA-10
However, when using Collections.sort(), the output in test log displays:
AA-1
AA-10
AA-2
AA-2 (1)
That’s why I am not able to verify if sorted data in the page and output of Collections.sort() are matched/equal on array list.
Please help me to figure out a simple way how to verify sorting in Katalon. Thanks!
hi,
your point is validate just the order not are lists equal?
hello,
this is one way to verify are lists equal
import static com.kms.katalon.core.checkpoint.CheckpointFactory.findCheckpoint
import static com.kms.katalon.core.testcase.TestCaseFactory.findTestCase
import static com.kms.katalon.core.testdata.TestDataFactory.findTestData
import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject
import static com.kms.katalon.core.testobject.ObjectRepository.findWindowsObject
import java.util.List
import com.kms.katalon.core.annotation.Keyword
import com.kms.katalon.core.checkpoint.Checkpoint as Checkpoint
import com.kms.katalon.core.cucumber.keyword.CucumberBuiltinKeywords as CucumberKW
import com.kms.katalon.core.mobile.keyword.MobileBuiltInKeywords as Mobile
import com.kms.katalon.core.model.FailureHandling as FailureHandling
import com.kms.katalon.core.testcase.TestCase as TestCase
import com.kms.katalon.core.testdata.TestData as TestData
import com.kms.katalon.core.testobject.TestObject as TestObject
import com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords as WS
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
import com.kms.katalon.core.windows.keyword.WindowsBuiltinKeywords as Windows
import internal.GlobalVariable as GlobalVariable
import com.kms.katalon.core.logging.KeywordLogger
KeywordLogger logger = new KeywordLogger()
List <String> arr = new ArrayList<>()
List <String> arr2 = new ArrayList<>()
//AA-1, AA-10, AA-2, AA-2 (1)
arr.add("AA-1")
arr.add("AA-10")
arr.add("AA-2")
arr.add("AA-2 (1)")
arr.add("BB")
arr2.add("AA-10")
arr2.add("AA-1")
arr2.add("AA-2 (1)")
arr2.add("AA-2")
print arr
print arr2
Collections.sort(arr, Collections.reverseOrder());
Collections.sort(arr2, Collections.reverseOrder());
// Here aList is an ArrayList of ArrayLists
ArrayList<ArrayList<String> > aList = new ArrayList<ArrayList<String> >(n);
aList = getNameListsCompared(arr, arr2)
if (aList.get(0).size > 0)
{
logger.logFailed("Missing elements from list two: ")
print ("Missing elements from list two: ")
for (int a = 0; a < aList.get(0).size(); a++){
print "missing name: "+aList.get(0).get(a)
logger.logFailed("missing name: "+aList.get(0).get(a))
}
}
else{
logger.logInfo("No missing elements from list two: ")
print ("No missing elements from list two: ")
}
if (aList.get(1).size() > 0){
logger.logFailed("Missing elements from list one: ")
print ("Missing elements from list one: ")
for (int b = 0; b < aList.get(1).size(); b++){
print "missing name: "+aList.get(1).get(b)
logger.logFailed("missing name: "+aList.get(1).get(b))
}
}
else{
logger.logInfo("No missing elements from list one: ")
print ("No missing elements from list one: ")
}
public ArrayList<ArrayList<String>> getNameListsCompared(List<String> arr, List<String> arr2){
int n = 0;
if (arr.size() > arr2.size()){
n = arr.size()
}
else{
n = arr2.size()
}
// Here aList is an ArrayList of ArrayLists
ArrayList<ArrayList<String> > aList = new ArrayList<ArrayList<String> >(n);
List <String> listOne = new ArrayList<>();
List <String> listTwo = new ArrayList<>();
listOne = arr
listTwo = arr2
//find missing elements from list two
listOne.removeAll(listTwo);
//println "missing elements from list two " + listOne;
aList.add(listOne)
listOne = arr
listTwo = arr2
//find missing elements from list one
listTwo.removeAll(listOne);
//println "missing elements from list one " + listTwo;
aList.add(listTwo)
listOne = arr
listTwo = arr2
//get common elements
listTwo.retainAll(listOne);
//println "common elements are: " + listTwo;
aList.add(listTwo)
listOne = arr
listTwo = arr2
HashSet<String> set = new HashSet<String>();
for (int i = 0; i < listOne.size; i++)
{
for (int j = 0; j < listTwo.size; j++)
{
if(listOne[i].equals(listTwo[j]))
{
set.add(listOne[i]);
}
}
}
//System.out.println("Common names are: "+set);
return aList
}
2020-04-15 17:59:32.655 ERROR c.k.katalon.core.logging.KeywordLogger - Missing elements from list two:
2020-04-15 17:59:32.665 ERROR c.k.katalon.core.logging.KeywordLogger - missing name: BB
Yes, I need to validate if the page displays the data table in ascending order. So I am thinking that the logic would be:
- Click the column header to make it in ascending order.
- Get the data on the sorted column then store it in array (e.g. Arr1).
- Get the data from Arr1 then store it in Arr2.
- Sort the data in Arr2 using Collections.sort() method.
- Verify if the stored data in Arr1[0] is equal to Arr2[0] to check that the data on the application is sorted in ascending format.
hi,
didn’t get your point in this phase
“Get the data from Arr1 then store it in Arr2.”
why to move sorted array to arr2 and sort again in step 4?
hi,
arr.add(“AA-1”)
arr.add(“AA-10”)
arr.add(“AA-2”)
arr.add(“AA-2 (1)”)
arr2.add(“AA-10”)
arr2.add(“AA-1”)
arr2.add(“AA-2 (1)”)
arr2.add(“AA-2”)
you can get the order as reversed order (descending)
Collections.sort(arr, Collections.reverseOrder());
Collections.sort(arr2, Collections.reverseOrder());
print arr
print arr2
[AA-2 (1), AA-2, AA-10, AA-1]
[AA-2 (1), AA-2, AA-10, AA-1]
Apologies if its confusing, but the purpose of that is:
Arr1 - serves as the “actual behavior” (what is being displayed on the UI of the application under the column that is clicked on to sort in ascending order)
Arr2 - will serve as the “expected behavior” using Collections.sort()
Then, it will verify if Arr1[0] is equal to Arr2[0] – which is the step 5
This is the “Actual Result” (which is correct because the testing of the manual QA team is from smallest to highest number):
AA-1
AA-2
AA-2 (1)
AA-10
But when using the Collections.sort(), the output is different from the Actual Result, that’s why the array list that I’m setting as Expected Result is not equal from the actual. That’s the main concern for now.
AA-1
AA-10
AA-2
AA-2 (1)
hi,
this will sort arr2 as it is in arr1
//Collections.sort(arr, Collections.reverseOrder());
Collections.sort(arr2, Collections.reverseOrder());
//print arr
//print arr2
//Collections.sort(arr, Collections.reverseOrder());
Collections.sort(arr2);
print arr
print arr2
[AA-1, AA-10, AA-2, AA-2 (1)]
[AA-1, AA-10, AA-2, AA-2 (1)]
It looks to me as though the application is using a combination sor,. alpha-hyphen-alpha
whereas the Collections sort is straight alpha.
I’m not an expert on Java/Groovy sorting. These guys may be able to help:
@Brandon_Hein @kazurayam
Collections.sort() for Strings is based on the ASCII code of each character in the String. That’s why you get this sorting:
AA-1
AA-10
AA-2 (1)
instead of:
AA-1
AA-2 (1)
AA-10
because it’s not read as “2” vs. “10”, but rather “2” vs. “1” with some chars after…
You will likely need to implement a custom Comparator to do this.
1 Like
I have developed an example Comparator class; published at
Getting started
Try running Test Cases/main/TC1
import com.kazurayam.katalonforum.CustomStringComparator
import java.util.Arrays
import java.util.Collections
import java.util.List
import java.util.regex.Pattern
import java.util.regex.Matcher
String[] arr = ["AA-1", "AA-2", "AA-2 (1)", "AA-10"]
List expected = Arrays.asList(arr)
assert expected != null
assert expected[0] == "AA-1"
assert expected[1] == "AA-2"
assert expected[2] == "AA-2 (1)"
assert expected[3] == "AA-10"
List sorted1 = Arrays.asList(arr)
Collections.sort(sorted1)
assert sorted1 != null
assert sorted1[0] == "AA-1"
assert sorted1[1] == "AA-10"
assert sorted1[2] == "AA-2"
assert sorted1[3] == "AA-2 (1)"
List sorted2 = Arrays.asList(arr)
Collections.sort(sorted2, new CustomStringComparator())
assert sorted2 != null
assert sorted2[0] == "AA-1"
assert sorted2[1] == "AA-2"
assert sorted2[2] == "AA-2 (1)"
assert sorted2[3] == "AA-10"
where you can see a set of sample code working.
- given with an array of String:
["AA-1", "AA-2", "AA-2 (1)", "AA-10"]
- how
Collections.sort()
without Comparator works
- and how
Collections.sort()
with CustomStringComparator
works
You can find the source of com.kazurayam.katalonforum.CustomStringComparator
class here.
My opinion
Developing com.kazurayam.katalonforum.CustomStringComparator
class required seasoned skill of Java/Groovy programming. It involved unit-tests using JUnit. This exercises would require a few years of intensive Java programming lessons.
I think that it is too much for a UI tester; a UI tester should not be responsible for verifying the data-sorting algorithms. I would rather rely on the server-side developers to test the AUT thoroughly enough.
One thing I will say, if you know what the list should look like before hand, and that list doesn’t change between any two executions of the same test, you could:
1.) Build the “expected” list by hand, with the expected order.
2.) Sort the column in the application
3.) Get the “actual” list from the column in the application, after sorting.
4.) Compare
But I imagine that the list is probably not static.
or 5. sort both list (expected and actual) before to compare them
ooor, we can do some ‘abomination’ wrt code optimization, without sorting:
- check both lists have the same length.
- check every element in list A is present in list B
- check each element in list B is present in list A
Yes, the list is not static.
This would invalidate the comparison though. OP is trying to validate that the column sorted the results correctly.
hi,
in python this is done in a few line
from natsort import natsorted
names = [‘AA-1’, ‘AA-10’, ‘AA-2’, ‘AA-2 (1)’]
print(natsorted(names, key=lambda y: y.lower()))
[‘AA-1’, ‘AA-2’, ‘AA-2 (1)’, ‘AA-10’]
will try to find out how to call python from java with arguments
and this java will do it too
import java.text.Collator;
import java.text.RuleBasedCollator;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
import static java.util.Collections.shuffle;
import static java.util.stream.Collectors.joining;
List<String> list = new ArrayList<String>();
list.add("AA-10");
list.add("AA-1");
list.add("AA-2 (1)");
list.add("AA-2");
RuleBasedCollator localRules = (RuleBasedCollator) Collator.getInstance();
String extraRules = IntStream.range(0, 100).mapToObj(String::valueOf).collect(joining(" < "));
RuleBasedCollator c = new RuleBasedCollator(localRules.getRules() + " & " + extraRules);
shuffle(list);
list.sort(c);
System.out.println(list);
[AA-1, AA-2, AA-2 (1), AA-10]
1 Like
@Timo_Kuisma1
Thank you for your code. I learned it. I did not know Collator
.
I rewrote your Java code into Groovy, which is runnable as a TestCase in Katalon Studio.
import static java.util.Collections.shuffle;
import static java.util.stream.Collectors.joining;
import java.text.Collator;
import java.text.RuleBasedCollator;
import java.util.stream.IntStream;
List<String> list = new ArrayList<String>();
list.add("AA-10");
list.add("AA-1");
list.add("AA-2 (1)");
list.add("AA-2");
RuleBasedCollator localRules = (RuleBasedCollator) Collator.getInstance();
String extraRules = IntStream.range(0, 100).mapToObj(String.&valueOf).collect(joining(" < "));
println "extraRules=" + extraRules
RuleBasedCollator c = new RuleBasedCollator(localRules.getRules() + " & " + extraRules);
shuffle(list);
list.sort(c);
System.out.println(list);
// [AA-1, AA-2, AA-2 (1), AA-10]
I changed String::valueOf
to String.&valueOf
.
1 Like